Skip to content

Commit deec6a9

Browse files
authored
Rollup merge of #79554 - b-naber:generic-associated-types-in-trait-paths, r=jackh726
Generic associated types in trait paths This is the second part of #78978 This should fix: Fixes #67510 Fixes #68648 Fixes #68649 Fixes #68650 Fixes #68652 Fixes #74684 Fixes #76535 Fixes #79422 Fixes #80433 and implement the remaining functionality needed for #44265 r? ``@matthewjasper``
2 parents 9e5d58f + 12d411f commit deec6a9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1051
-112
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -1076,16 +1076,40 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10761076
fn lower_assoc_ty_constraint(
10771077
&mut self,
10781078
constraint: &AssocTyConstraint,
1079-
itctx: ImplTraitContext<'_, 'hir>,
1079+
mut itctx: ImplTraitContext<'_, 'hir>,
10801080
) -> hir::TypeBinding<'hir> {
10811081
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
10821082

1083-
if let Some(ref gen_args) = constraint.gen_args {
1084-
self.sess.span_fatal(
1085-
gen_args.span(),
1086-
"generic associated types in trait paths are currently not implemented",
1087-
);
1088-
}
1083+
// lower generic arguments of identifier in constraint
1084+
let gen_args = if let Some(ref gen_args) = constraint.gen_args {
1085+
let gen_args_ctor = match gen_args {
1086+
GenericArgs::AngleBracketed(ref data) => {
1087+
self.lower_angle_bracketed_parameter_data(
1088+
data,
1089+
ParamMode::Explicit,
1090+
itctx.reborrow(),
1091+
)
1092+
.0
1093+
}
1094+
GenericArgs::Parenthesized(ref data) => {
1095+
let mut err = self.sess.struct_span_err(
1096+
gen_args.span(),
1097+
"parenthesized generic arguments cannot be used in associated type constraints"
1098+
);
1099+
// FIXME: try to write a suggestion here
1100+
err.emit();
1101+
self.lower_angle_bracketed_parameter_data(
1102+
&data.as_angle_bracketed_args(),
1103+
ParamMode::Explicit,
1104+
itctx.reborrow(),
1105+
)
1106+
.0
1107+
}
1108+
};
1109+
self.arena.alloc(gen_args_ctor.into_generic_args(&self.arena))
1110+
} else {
1111+
self.arena.alloc(hir::GenericArgs::none())
1112+
};
10891113

10901114
let kind = match constraint.kind {
10911115
AssocTyConstraintKind::Equality { ref ty } => {
@@ -1182,6 +1206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11821206
hir::TypeBinding {
11831207
hir_id: self.lower_node_id(constraint.id),
11841208
ident: constraint.ident,
1209+
gen_args,
11851210
kind,
11861211
span: constraint.span,
11871212
}

compiler/rustc_ast_lowering/src/path.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
362362
}
363363
}
364364

365-
fn lower_angle_bracketed_parameter_data(
365+
pub(crate) fn lower_angle_bracketed_parameter_data(
366366
&mut self,
367367
data: &AngleBracketedArgs,
368368
param_mode: ParamMode,
@@ -426,6 +426,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
426426
) -> hir::TypeBinding<'hir> {
427427
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
428428
let kind = hir::TypeBindingKind::Equality { ty };
429-
hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
429+
let args = arena_vec![self;];
430+
let bindings = arena_vec![self;];
431+
let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false });
432+
hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
430433
}
431434
}

compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,7 @@ pub struct TypeBinding<'hir> {
20152015
pub hir_id: HirId,
20162016
#[stable_hasher(project(name))]
20172017
pub ident: Ident,
2018+
pub gen_args: &'hir GenericArgs<'hir>,
20182019
pub kind: TypeBindingKind<'hir>,
20192020
pub span: Span,
20202021
}

compiler/rustc_hir/src/intravisit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
781781
) {
782782
visitor.visit_id(type_binding.hir_id);
783783
visitor.visit_ident(type_binding.ident);
784+
visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
784785
match type_binding.kind {
785786
TypeBindingKind::Equality { ref ty } => {
786787
visitor.visit_ty(ty);

compiler/rustc_hir_pretty/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,7 @@ impl<'a> State<'a> {
18401840
for binding in generic_args.bindings.iter() {
18411841
start_or_comma(self);
18421842
self.print_ident(binding.ident);
1843+
self.print_generic_args(binding.gen_args, false, false);
18431844
self.s.space();
18441845
match generic_args.bindings[0].kind {
18451846
hir::TypeBindingKind::Equality { ref ty } => {

compiler/rustc_middle/src/ty/sty.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1132,8 +1132,16 @@ impl<'tcx> ProjectionTy<'tcx> {
11321132
/// For example, if this is a projection of `<T as Iterator>::Item`,
11331133
/// then this function would return a `T: Iterator` trait reference.
11341134
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
1135+
// FIXME: This method probably shouldn't exist at all, since it's not
1136+
// clear what this method really intends to do. Be careful when
1137+
// using this method since the resulting TraitRef additionally
1138+
// contains the substs for the assoc_item, which strictly speaking
1139+
// is not correct
11351140
let def_id = tcx.associated_item(self.item_def_id).container.id();
1136-
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
1141+
// Include substitutions for generic arguments of associated types
1142+
let assoc_item = tcx.associated_item(self.item_def_id);
1143+
let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
1144+
ty::TraitRef { def_id, substs: substs_assoc_item }
11371145
}
11381146

11391147
pub fn self_ty(&self) -> Ty<'tcx> {

compiler/rustc_trait_selection/src/traits/object_safety.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,11 @@ fn predicates_reference_self(
257257
}
258258

259259
fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
260-
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
261260
tcx.associated_items(trait_def_id)
262261
.in_definition_order()
263262
.filter(|item| item.kind == ty::AssocKind::Type)
264263
.flat_map(|item| tcx.explicit_item_bounds(item.def_id))
265-
.map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
266-
.filter_map(|predicate| predicate_references_self(tcx, predicate))
264+
.filter_map(|pred_span| predicate_references_self(tcx, *pred_span))
267265
.collect()
268266
}
269267

compiler/rustc_typeck/src/astconv/mod.rs

+104-62
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,15 @@ pub enum SizedByDefault {
112112
No,
113113
}
114114

115+
#[derive(Debug)]
115116
struct ConvertedBinding<'a, 'tcx> {
116117
item_name: Ident,
117118
kind: ConvertedBindingKind<'a, 'tcx>,
119+
gen_args: &'a GenericArgs<'a>,
118120
span: Span,
119121
}
120122

123+
#[derive(Debug)]
121124
enum ConvertedBindingKind<'a, 'tcx> {
122125
Equality(Ty<'tcx>),
123126
Constraint(&'a [hir::GenericBound<'a>]),
@@ -323,6 +326,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
323326

324327
let tcx = self.tcx();
325328
let generics = tcx.generics_of(def_id);
329+
debug!("generics: {:?}", generics);
326330

327331
if generics.has_self {
328332
if generics.parent.is_some() {
@@ -557,7 +561,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
557561
ConvertedBindingKind::Constraint(bounds)
558562
}
559563
};
560-
ConvertedBinding { item_name: binding.ident, kind, span: binding.span }
564+
ConvertedBinding {
565+
item_name: binding.ident,
566+
kind,
567+
gen_args: binding.gen_args,
568+
span: binding.span,
569+
}
561570
})
562571
.collect();
563572

@@ -918,60 +927,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
918927
dup_bindings: &mut FxHashMap<DefId, Span>,
919928
path_span: Span,
920929
) -> Result<(), ErrorReported> {
921-
let tcx = self.tcx();
922-
923-
if !speculative {
924-
// Given something like `U: SomeTrait<T = X>`, we want to produce a
925-
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
926-
// subtle in the event that `T` is defined in a supertrait of
927-
// `SomeTrait`, because in that case we need to upcast.
928-
//
929-
// That is, consider this case:
930-
//
931-
// ```
932-
// trait SubTrait: SuperTrait<i32> { }
933-
// trait SuperTrait<A> { type T; }
934-
//
935-
// ... B: SubTrait<T = foo> ...
936-
// ```
937-
//
938-
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
939-
940-
// Find any late-bound regions declared in `ty` that are not
941-
// declared in the trait-ref. These are not well-formed.
942-
//
943-
// Example:
944-
//
945-
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
946-
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
947-
if let ConvertedBindingKind::Equality(ty) = binding.kind {
948-
let late_bound_in_trait_ref =
949-
tcx.collect_constrained_late_bound_regions(&trait_ref);
950-
let late_bound_in_ty =
951-
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
952-
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
953-
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
930+
// Given something like `U: SomeTrait<T = X>`, we want to produce a
931+
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
932+
// subtle in the event that `T` is defined in a supertrait of
933+
// `SomeTrait`, because in that case we need to upcast.
934+
//
935+
// That is, consider this case:
936+
//
937+
// ```
938+
// trait SubTrait: SuperTrait<i32> { }
939+
// trait SuperTrait<A> { type T; }
940+
//
941+
// ... B: SubTrait<T = foo> ...
942+
// ```
943+
//
944+
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
954945

955-
// FIXME: point at the type params that don't have appropriate lifetimes:
956-
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
957-
// ---- ---- ^^^^^^^
958-
self.validate_late_bound_regions(
959-
late_bound_in_trait_ref,
960-
late_bound_in_ty,
961-
|br_name| {
962-
struct_span_err!(
963-
tcx.sess,
964-
binding.span,
965-
E0582,
966-
"binding for associated type `{}` references {}, \
967-
which does not appear in the trait input types",
968-
binding.item_name,
969-
br_name
970-
)
971-
},
972-
);
973-
}
974-
}
946+
debug!(
947+
"add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
948+
hir_ref_id, trait_ref, binding, bounds
949+
);
950+
let tcx = self.tcx();
975951

976952
let candidate =
977953
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
@@ -1030,20 +1006,85 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10301006
.or_insert(binding.span);
10311007
}
10321008

1009+
// Include substitutions for generic parameters of associated types
1010+
let projection_ty = candidate.map_bound(|trait_ref| {
1011+
let item_segment = hir::PathSegment {
1012+
ident: assoc_ty.ident,
1013+
hir_id: None,
1014+
res: None,
1015+
args: Some(binding.gen_args),
1016+
infer_args: false,
1017+
};
1018+
1019+
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
1020+
tcx,
1021+
path_span,
1022+
assoc_ty.def_id,
1023+
&item_segment,
1024+
trait_ref.substs,
1025+
);
1026+
1027+
debug!(
1028+
"add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
1029+
substs_trait_ref_and_assoc_item
1030+
);
1031+
1032+
ty::ProjectionTy {
1033+
item_def_id: assoc_ty.def_id,
1034+
substs: substs_trait_ref_and_assoc_item,
1035+
}
1036+
});
1037+
1038+
if !speculative {
1039+
// Find any late-bound regions declared in `ty` that are not
1040+
// declared in the trait-ref or assoc_ty. These are not well-formed.
1041+
//
1042+
// Example:
1043+
//
1044+
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
1045+
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
1046+
if let ConvertedBindingKind::Equality(ty) = binding.kind {
1047+
let late_bound_in_trait_ref =
1048+
tcx.collect_constrained_late_bound_regions(&projection_ty);
1049+
let late_bound_in_ty =
1050+
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
1051+
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
1052+
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
1053+
1054+
// FIXME: point at the type params that don't have appropriate lifetimes:
1055+
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
1056+
// ---- ---- ^^^^^^^
1057+
self.validate_late_bound_regions(
1058+
late_bound_in_trait_ref,
1059+
late_bound_in_ty,
1060+
|br_name| {
1061+
struct_span_err!(
1062+
tcx.sess,
1063+
binding.span,
1064+
E0582,
1065+
"binding for associated type `{}` references {}, \
1066+
which does not appear in the trait input types",
1067+
binding.item_name,
1068+
br_name
1069+
)
1070+
},
1071+
);
1072+
}
1073+
}
1074+
10331075
match binding.kind {
10341076
ConvertedBindingKind::Equality(ref ty) => {
10351077
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
10361078
// the "projection predicate" for:
10371079
//
10381080
// `<T as Iterator>::Item = u32`
10391081
bounds.projection_bounds.push((
1040-
candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
1041-
projection_ty: ty::ProjectionTy::from_ref_and_name(
1042-
tcx,
1043-
trait_ref,
1044-
binding.item_name,
1045-
),
1046-
ty,
1082+
projection_ty.map_bound(|projection_ty| {
1083+
debug!(
1084+
"add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
1085+
projection_ty, projection_ty.substs
1086+
);
1087+
ty::ProjectionPredicate { projection_ty, ty }
10471088
}),
10481089
binding.span,
10491090
));
@@ -1055,7 +1096,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10551096
//
10561097
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
10571098
// parameter to have a skipped binder.
1058-
let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
1099+
let param_ty =
1100+
tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs);
10591101
self.add_bounds(param_ty, ast_bounds, bounds);
10601102
}
10611103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(generic_associated_types)]
2+
//~^ WARNING: the feature `generic_associated_types` is incomplete
3+
4+
trait X {
5+
type Y<'x>;
6+
}
7+
8+
fn main() {
9+
fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
10+
//~^ ERROR: use of undeclared lifetime name `'x`
11+
//~| ERROR: binding for associated type `Y` references lifetime
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/gat-in-trait-path-undeclared-lifetime.rs:1:12
3+
|
4+
LL | #![feature(generic_associated_types)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
9+
10+
error[E0261]: use of undeclared lifetime name `'x`
11+
--> $DIR/gat-in-trait-path-undeclared-lifetime.rs:9:35
12+
|
13+
LL | fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
14+
| - ^^ undeclared lifetime
15+
| |
16+
| help: consider introducing lifetime `'x` here: `<'x>`
17+
|
18+
= help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
19+
20+
error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types
21+
--> $DIR/gat-in-trait-path-undeclared-lifetime.rs:9:33
22+
|
23+
LL | fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
24+
| ^^^^^^^^^^^^^^^^^
25+
26+
error: aborting due to 2 previous errors; 1 warning emitted
27+
28+
Some errors have detailed explanations: E0261, E0582.
29+
For more information about an error, try `rustc --explain E0261`.

0 commit comments

Comments
 (0)