Skip to content

Commit 3816958

Browse files
committed
Implemented for function bounds, type bounds, and named existential types.
1 parent dce27cb commit 3816958

File tree

17 files changed

+367
-196
lines changed

17 files changed

+367
-196
lines changed

src/librustc/hir/lowering.rs

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ use syntax::symbol::{kw, sym, Symbol};
6969
use syntax::tokenstream::{TokenStream, TokenTree};
7070
use syntax::parse::token::Token;
7171
use syntax::visit::{self, Visitor};
72-
use syntax_pos::{edition, Span};
72+
use syntax_pos::{DUMMY_SP, edition, Span};
7373

7474
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
7575

@@ -191,9 +191,9 @@ enum ImplTraitContext<'a> {
191191
/// equivalent to a fresh existential parameter like `existential type T; fn foo() -> T`.
192192
///
193193
/// We optionally store a `DefId` for the parent item here so we can look up necessary
194-
/// information later. It is `None` when no information about the context should be stored,
195-
/// e.g., for consts and statics.
196-
Existential(Option<DefId>),
194+
/// information later. It is `None` when no information about the context should be stored
195+
/// (e.g., for consts and statics).
196+
Existential(Option<DefId> /* fn def-ID */),
197197

198198
/// `impl Trait` is not accepted in this position.
199199
Disallowed(ImplTraitPosition),
@@ -216,7 +216,7 @@ impl<'a> ImplTraitContext<'a> {
216216
use self::ImplTraitContext::*;
217217
match self {
218218
Universal(params) => Universal(params),
219-
Existential(did) => Existential(*did),
219+
Existential(fn_def_id) => Existential(*fn_def_id),
220220
Disallowed(pos) => Disallowed(*pos),
221221
}
222222
}
@@ -1342,13 +1342,36 @@ impl<'a> LoweringContext<'a> {
13421342
}
13431343
}
13441344

1345-
fn lower_ty_binding(&mut self, b: &TypeBinding,
1346-
itctx: ImplTraitContext<'_>) -> hir::TypeBinding {
1345+
fn lower_assoc_ty_constraint(&mut self,
1346+
c: &AssocTyConstraint,
1347+
itctx: ImplTraitContext<'_>)
1348+
-> hir::TypeBinding {
1349+
let ty = match c.kind {
1350+
AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
1351+
AssocTyConstraintKind::Bound { ref bounds } => {
1352+
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
1353+
let impl_ty_node_id = self.sess.next_node_id();
1354+
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
1355+
self.resolver.definitions().create_def_with_parent(
1356+
parent_def_index,
1357+
impl_ty_node_id,
1358+
DefPathData::Misc,
1359+
DefIndexAddressSpace::High,
1360+
Mark::root(),
1361+
DUMMY_SP);
1362+
self.lower_ty(&Ty {
1363+
id: self.sess.next_node_id(),
1364+
node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
1365+
span: DUMMY_SP,
1366+
}, itctx)
1367+
}
1368+
};
1369+
13471370
hir::TypeBinding {
1348-
hir_id: self.lower_node_id(b.id),
1349-
ident: b.ident,
1350-
ty: self.lower_ty(&b.ty, itctx),
1351-
span: b.span,
1371+
hir_id: self.lower_node_id(c.id),
1372+
ident: c.ident,
1373+
ty
1374+
span: c.span,
13521375
}
13531376
}
13541377

@@ -1604,7 +1627,7 @@ impl<'a> LoweringContext<'a> {
16041627
origin: hir::ExistTyOrigin::ReturnImplTrait,
16051628
};
16061629

1607-
trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
1630+
trace!("exist ty from impl trait def-index: {:#?}", exist_ty_def_index);
16081631
let exist_ty_id = lctx.generate_existential_type(
16091632
exist_ty_node_id,
16101633
exist_ty_item,
@@ -1617,7 +1640,7 @@ impl<'a> LoweringContext<'a> {
16171640
})
16181641
}
16191642

1620-
/// Registers a new existential type with the proper NodeIds and
1643+
/// Registers a new existential type with the proper `NodeId`ss and
16211644
/// returns the lowered node ID for the existential type.
16221645
fn generate_existential_type(
16231646
&mut self,
@@ -2195,15 +2218,16 @@ impl<'a> LoweringContext<'a> {
21952218
param_mode: ParamMode,
21962219
mut itctx: ImplTraitContext<'_>,
21972220
) -> (hir::GenericArgs, bool) {
2198-
let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
2221+
let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
21992222
let has_types = args.iter().any(|arg| match arg {
22002223
ast::GenericArg::Type(_) => true,
22012224
_ => false,
22022225
});
22032226
(
22042227
hir::GenericArgs {
22052228
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
2206-
bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(),
2229+
bindings: constraints.iter().map(
2230+
|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())).collect(),
22072231
parenthesized: false,
22082232
},
22092233
!has_types && param_mode == ParamMode::Optional
@@ -3236,12 +3260,14 @@ impl<'a> LoweringContext<'a> {
32363260
self.lower_ty(t, ImplTraitContext::disallowed()),
32373261
self.lower_generics(generics, ImplTraitContext::disallowed()),
32383262
),
3239-
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy {
3240-
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
3241-
bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
3242-
impl_trait_fn: None,
3243-
origin: hir::ExistTyOrigin::ExistentialType,
3244-
}),
3263+
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
3264+
hir::ExistTy {
3265+
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
3266+
bounds: self.lower_param_bounds(b, ImplTraitContext::Existential(None)),
3267+
impl_trait_fn: None,
3268+
origin: hir::ExistTyOrigin::ExistentialType,
3269+
},
3270+
),
32453271
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
32463272
hir::EnumDef {
32473273
variants: enum_definition

src/librustc/hir/map/definitions.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,11 @@ impl Definitions {
397397
self.node_to_hir_id[node_id]
398398
}
399399

400+
#[inline]
401+
pub fn def_index_to_node_id(&self, def_index: DefIndex) -> ast::NodeId {
402+
self.as_local_node_id(DefId::local(def_index)).unwrap()
403+
}
404+
400405
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists
401406
/// and it's not `DUMMY_SP`.
402407
#[inline]

src/librustc/hir/map/mod.rs

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ impl<'hir> Map<'hir> {
288288

289289
#[inline]
290290
pub fn def_index_to_node_id(&self, def_index: DefIndex) -> NodeId {
291-
self.definitions.as_local_node_id(DefId::local(def_index)).unwrap()
291+
self.definitions.def_index_to_node_id(def_index)
292292
}
293293

294294
#[inline]
@@ -649,16 +649,16 @@ impl<'hir> Map<'hir> {
649649
result
650650
}
651651

652-
/// Similar to `get_parent`; returns the parent node-id, or own `id` if there is
653-
/// no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself
654-
/// present in the map -- so passing the return value of get_parent_node to
655-
/// get may actually panic.
656-
/// This function returns the immediate parent in the AST, whereas get_parent
652+
/// Similar to `get_parent`; returns the parent node-ID, or just `hir_id` if there
653+
/// is no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself
654+
/// present in the map, so passing the return value of `get_parent_node` to
655+
/// `get` may in fact panic.
656+
/// This function returns the immediate parent in the AST, whereas `get_parent`
657657
/// returns the enclosing item. Note that this might not be the actual parent
658-
/// node in the AST - some kinds of nodes are not in the map and these will
659-
/// never appear as the parent_node. So you can always walk the `parent_nodes`
660-
/// from a node to the root of the ast (unless you get the same ID back here
661-
/// that can happen if the ID is not in the map itself or is just weird).
658+
/// node in the AST -- some kinds of nodes are not in the map and these will
659+
/// never appear as the parent node. Thus, you can always walk the parent nodes
660+
/// from a node to the root of the AST (unless you get back the same ID here,
661+
/// which can happen if the ID is not in the map itself or is just weird).
662662
pub fn get_parent_node(&self, id: NodeId) -> NodeId {
663663
let hir_id = self.node_to_hir_id(id);
664664
let parent_hir_id = self.get_parent_node_by_hir_id(hir_id);
@@ -841,21 +841,66 @@ impl<'hir> Map<'hir> {
841841
}
842842
}
843843

844-
/// Returns the nearest enclosing scope. A scope is an item or block.
845-
/// FIXME: it is not clear to me that all items qualify as scopes -- statics
846-
/// and associated types probably shouldn't, for example. Behavior in this
847-
/// regard should be expected to be highly unstable.
848-
pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
844+
/// Returns the nearest enclosing scope. A scope is roughly an item or block.
845+
pub fn get_enclosing_scope(&self, id: HirId) -> Option<HirId> {
849846
self.walk_parent_nodes(hir_id, |node| match *node {
850-
Node::Item(_) |
851-
Node::ForeignItem(_) |
852-
Node::TraitItem(_) |
853-
Node::ImplItem(_) |
847+
Node::Item(i) => {
848+
match i.node {
849+
ItemKind::Fn(..)
850+
| ItemKind::Mod(..)
851+
| ItemKind::Enum(..)
852+
| ItemKind::Struct(..)
853+
| ItemKind::Union(..)
854+
| ItemKind::Trait(..)
855+
| ItemKind::Impl(..) => true,
856+
_ => false,
857+
}
858+
},
859+
Node::ForeignItem(fi) => {
860+
match fi.node {
861+
ForeignItemKind::Fn(..) => true,
862+
_ => false,
863+
}
864+
},
865+
Node::TraitItem(ti) => {
866+
match ti.node {
867+
TraitItemKind::Method(..) => true,
868+
_ => false,
869+
}
870+
},
871+
Node::ImplItem(ii) => {
872+
match ii.node {
873+
ImplItemKind::Method(..) => true,
874+
_ => false,
875+
}
876+
},
854877
Node::Block(_) => true,
855878
_ => false,
856879
}, |_| false).ok()
857880
}
858881

882+
/// Returns the defining scope for an existential type definition.
883+
pub fn get_defining_scope(&self, id: NodeId) -> Option<NodeId> {
884+
let mut scope = id;
885+
loop {
886+
scope = self.get_enclosing_scope(scope)?;
887+
if scope == CRATE_NODE_ID {
888+
return Some(CRATE_NODE_ID);
889+
}
890+
match self.get(scope) {
891+
Node::Item(i) => {
892+
match i.node {
893+
ItemKind::Existential(ExistTy { impl_trait_fn: None, .. }) => {}
894+
_ => break,
895+
}
896+
}
897+
Node::Block(_) => {}
898+
_ => break,
899+
}
900+
}
901+
Some(scope)
902+
}
903+
859904
pub fn get_parent_did(&self, id: NodeId) -> DefId {
860905
let hir_id = self.node_to_hir_id(id);
861906
self.get_parent_did_by_hir_id(hir_id)

src/librustc/infer/opaque_types/mod.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -786,13 +786,13 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
786786
match tcx.hir().find_by_hir_id(opaque_hir_id)
787787
{
788788
Some(Node::Item(item)) => match item.node {
789-
// impl trait
789+
// Anonymous `impl Trait`
790790
hir::ItemKind::Existential(hir::ExistTy {
791791
impl_trait_fn: Some(parent),
792792
origin,
793793
..
794794
}) => (parent == self.parent_def_id, origin),
795-
// named existential types
795+
// Named `existential type`
796796
hir::ItemKind::Existential(hir::ExistTy {
797797
impl_trait_fn: None,
798798
origin,
@@ -868,7 +868,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
868868

869869
let predicates_of = tcx.predicates_of(def_id);
870870
debug!(
871-
"instantiate_opaque_types: predicates: {:#?}",
871+
"instantiate_opaque_types: predicates={:#?}",
872872
predicates_of,
873873
);
874874
let bounds = predicates_of.instantiate(tcx, substs);
@@ -884,11 +884,11 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
884884
// (e.g., `existential type Foo<T: Bound>: Bar;` needs to be
885885
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
886886
debug!(
887-
"instantiate_opaque_types: param_env: {:#?}",
887+
"instantiate_opaque_types: param_env={:#?}",
888888
self.param_env,
889889
);
890890
debug!(
891-
"instantiate_opaque_types: generics: {:#?}",
891+
"instantiate_opaque_types: generics={:#?}",
892892
tcx.generics_of(def_id),
893893
);
894894

@@ -922,8 +922,9 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
922922
}
923923
}
924924

925-
/// Returns `true` if `opaque_node_id` is a sibling or a child of a sibling of `def_id`.
925+
/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
926926
///
927+
/// Example:
927928
/// ```rust
928929
/// pub mod foo {
929930
/// pub mod bar {
@@ -936,24 +937,28 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
936937
/// }
937938
/// ```
938939
///
939-
/// Here, `def_id` is the `DefId` of the existential type `Baz` and `opaque_node_id` is the
940-
/// `NodeId` of the reference to `Baz` (i.e., the return type of both `f1` and `f2`).
941-
/// We return `true` if the reference is within the same module as the existential type
942-
/// (i.e., `true` for `f1`, `false` for `f2`).
940+
/// Here, `def_id` is the `DefId` of the defining use of the existential type (e.g., `f1` or `f2`),
941+
/// and `opaque_hir_id` is the `HirId` of the definition of the existential type `Baz`.
942+
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
943943
pub fn may_define_existential_type(
944944
tcx: TyCtxt<'_, '_, '_>,
945945
def_id: DefId,
946946
opaque_hir_id: hir::HirId,
947947
) -> bool {
948948
let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
949-
// Named existential types can be defined by any siblings or
950-
// children of siblings.
951-
let mod_id = tcx.hir().get_parent_item(opaque_hir_id);
952-
// We walk up the node tree until we hit the root or the parent
953-
// of the opaque type.
954-
while hir_id != mod_id && node_id != ast::CRATE_HIR_ID {
949+
trace!(
950+
"may_define_existential_type(def={:?}, opaque_node={:?})",
951+
tcx.hir().get(hir_id),
952+
tcx.hir().get(opaque_hir_id)
953+
);
954+
955+
// Named existential types can be defined by any siblings or children of siblings.
956+
let scope_id = tcx.hir().get_defining_scope(opaque_hir_id)
957+
.expect("could not get defining scope");
958+
// We walk up the node tree until we hit the root or the scope of the opaque type.
959+
while hir_id != scope_id && hir_id != ast::CRATE_hir_ID {
955960
hir_id = tcx.hir().get_parent_item(hir_id);
956961
}
957-
// Syntactically we are allowed to define the concrete type.
958-
hir_id == mod_id
962+
// Syntactically, we are allowed to define the concrete type if:
963+
hir_id == scope_id
959964
}

src/librustc/traits/select.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,8 +1848,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
18481848
.iter()
18491849
.filter_map(|o| o.to_opt_poly_trait_ref());
18501850

1851-
// micro-optimization: filter out predicates relating to different
1852-
// traits.
1851+
// Micro-optimization: filter out predicates relating to different traits.
18531852
let matching_bounds =
18541853
all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
18551854

src/librustc_interface/util.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,22 @@ impl<'a> ReplaceBodyWithLoop<'a> {
716716
ast::GenericArg::Type(ty) => Some(ty),
717717
_ => None,
718718
});
719+
let any_assoc_ty_bounds = data.constraints.iter().any(|c| {
720+
if let ast::AssocTyConstraintKind::Bound { .. } = c.kind {
721+
true
722+
} else {
723+
false
724+
}
725+
});
726+
any_assoc_ty_bounds ||
719727
any_involves_impl_trait(types.into_iter()) ||
720-
any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty))
728+
any_involves_impl_trait(data.constraints.iter().filter_map(|c| {
729+
if let ast::AssocTyConstraintKind::Equality { ref ty } = c.kind {
730+
Some(ty)
731+
} else {
732+
None
733+
}
734+
}))
721735
},
722736
Some(&ast::GenericArgs::Parenthesized(ref data)) => {
723737
any_involves_impl_trait(data.inputs.iter()) ||

0 commit comments

Comments
 (0)