Skip to content

Commit

Permalink
Implemented for traits (associated type definitions).
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Regueiro committed Jun 5, 2019
1 parent 3816958 commit aaa53ec
Show file tree
Hide file tree
Showing 12 changed files with 313 additions and 250 deletions.
3 changes: 3 additions & 0 deletions src/librustc/hir/intravisit.rs
Expand Up @@ -626,6 +626,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
TyKind::CVarArgs(ref lt) => {
visitor.visit_lifetime(lt)
}
TyKind::AssocTyExistential(ref bounds) => {
walk_list!(visitor, visit_param_bound, bounds);
}
TyKind::Infer | TyKind::Err => {}
}
}
Expand Down
54 changes: 37 additions & 17 deletions src/librustc/hir/lowering.rs
Expand Up @@ -195,6 +195,12 @@ enum ImplTraitContext<'a> {
/// (e.g., for consts and statics).
Existential(Option<DefId> /* fn def-ID */),

/// Treat `impl Trait` as a bound on the associated type applied to the trait.
/// Example: `trait Foo { type Bar: Iterator<Item = impl Debug>; }` is conceptually
/// equivalent to `trait Foo where <Self::Bar as Iterator>::Item: Debug
/// { type Bar: Iterator; }`.
AssociatedTy,

/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
}
Expand All @@ -217,6 +223,7 @@ impl<'a> ImplTraitContext<'a> {
match self {
Universal(params) => Universal(params),
Existential(fn_def_id) => Existential(*fn_def_id),
AssociatedTy => AssociatedTy,
Disallowed(pos) => Disallowed(*pos),
}
}
Expand Down Expand Up @@ -1537,6 +1544,16 @@ impl<'a> LoweringContext<'a> {
}),
))
}
ImplTraitContext::AssociatedTy => {
let hir_bounds = self.lower_param_bounds(
bounds,
ImplTraitContext::AssociatedTy,
);

hir::TyKind::AssocTyExistential(
hir_bounds,
)
}
ImplTraitContext::Disallowed(pos) => {
let allowed_in = if self.sess.features_untracked()
.impl_trait_in_bindings {
Expand Down Expand Up @@ -1640,8 +1657,8 @@ impl<'a> LoweringContext<'a> {
})
}

/// Registers a new existential type with the proper `NodeId`ss and
/// returns the lowered node ID for the existential type.
/// Registers a new existential type with the proper `NodeId`s and
/// returns the lowered node-ID for the existential type.
fn generate_existential_type(
&mut self,
exist_ty_node_id: NodeId,
Expand Down Expand Up @@ -2226,8 +2243,9 @@ impl<'a> LoweringContext<'a> {
(
hir::GenericArgs {
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
bindings: constraints.iter().map(
|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())).collect(),
bindings: constraints.iter()
.map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow()))
.collect(),
parenthesized: false,
},
!has_types && param_mode == ParamMode::Optional
Expand Down Expand Up @@ -3257,13 +3275,13 @@ impl<'a> LoweringContext<'a> {
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
self.lower_ty(t, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_ty(t, ImplTraitContext::AssociatedTy),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
),
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
hir::ExistTy {
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
bounds: self.lower_param_bounds(b, ImplTraitContext::Existential(None)),
generics: self.lower_generics(generics, ImplTraitContext::AssociatedTy),
bounds: self.lower_param_bounds(b, ImplTraitContext::AssociatedTy),
impl_trait_fn: None,
origin: hir::ExistTyOrigin::ExistentialType,
},
Expand All @@ -3276,20 +3294,20 @@ impl<'a> LoweringContext<'a> {
.map(|x| self.lower_variant(x))
.collect(),
},
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
),
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(struct_def);
hir::ItemKind::Struct(
struct_def,
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
hir::ItemKind::Union(
vdata,
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
)
}
ItemKind::Impl(
Expand Down Expand Up @@ -3656,15 +3674,17 @@ impl<'a> LoweringContext<'a> {
);
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
}
TraitItemKind::Type(ref bounds, ref default) => (
self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
TraitItemKind::Type(ref bounds, ref default) => {
let generics = self.lower_generics(&i.generics, ImplTraitContext::AssociatedTy);
let node = hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::AssociatedTy),
default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
),
),
);

(generics, node)
},
TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
};

Expand Down
2 changes: 2 additions & 0 deletions src/librustc/hir/mod.rs
Expand Up @@ -1898,6 +1898,8 @@ pub enum TyKind {
/// Placeholder for C-variadic arguments. We "spoof" the `VaList` created
/// from the variadic arguments. This type is only valid up to typeck.
CVarArgs(Lifetime),
/// The existential type (i.e., `impl Trait`) that constrains an associated type.
AssocTyExistential(HirVec<GenericBound>),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/hir/print.rs
Expand Up @@ -409,6 +409,9 @@ impl<'a> State<'a> {
hir::TyKind::CVarArgs(_) => {
self.s.word("...")?;
}
hir::TyKind::AssocTyExistential(ref bounds) => {
self.print_bounds(":", bounds)?;
}
}
self.end()
}
Expand Down
12 changes: 7 additions & 5 deletions src/librustc/infer/opaque_types/mod.rs
Expand Up @@ -948,15 +948,17 @@ pub fn may_define_existential_type(
let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
trace!(
"may_define_existential_type(def={:?}, opaque_node={:?})",
tcx.hir().get(hir_id),
tcx.hir().get(opaque_hir_id)
tcx.hir().get_by_hir_id(hir_id),
tcx.hir().get_by_hir_id(opaque_hir_id)
);

// Named existential types can be defined by any siblings or children of siblings.
let scope_id = tcx.hir().get_defining_scope(opaque_hir_id)
.expect("could not get defining scope");
let scope_node_id = tcx.hir()
.get_defining_scope(tcx.hir().hir_to_node_id(opaque_hir_id))
.expect("could not get defining scope");
let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope_id && hir_id != ast::CRATE_hir_ID {
while hir_id != scope_id && hir_id != hir::CRATE_HIR_ID {
hir_id = tcx.hir().get_parent_item(hir_id);
}
// Syntactically, we are allowed to define the concrete type if:
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_interface/util.rs
Expand Up @@ -726,7 +726,8 @@ impl<'a> ReplaceBodyWithLoop<'a> {
any_assoc_ty_bounds ||
any_involves_impl_trait(types.into_iter()) ||
any_involves_impl_trait(data.constraints.iter().filter_map(|c| {
if let ast::AssocTyConstraintKind::Equality { ref ty } = c.kind {
if let ast::AssocTyConstraintKind::Equality { ref ty }
= c.kind {
Some(ty)
} else {
None
Expand Down
5 changes: 2 additions & 3 deletions src/librustc_privacy/lib.rs
Expand Up @@ -1040,12 +1040,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
if !self.in_body {
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
// The traits' privacy in bodies is already checked as a part of trait object types.
let (principal, projections) =
rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
if self.visit_trait(*principal.skip_binder()) {
return;
}
for (poly_predicate, _) in projections {
for (poly_predicate, _) in bounds.projection_bounds {
let tcx = self.tcx;
if self.visit(poly_predicate.skip_binder().ty) ||
self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
Expand Down

0 comments on commit aaa53ec

Please sign in to comment.