Skip to content

Commit b50c3b7

Browse files
authored
Rollup merge of #67160 - matthewjasper:gat-generics, r=nikomatsakis
Make GATs less ICE-prone. After this PR simple lifetime-generic associated types can now be used in a compiling program. There are two big limitations: * #30472 has not been addressed in any way (see src/test/ui/generic-associated-types/iterable.rs) * Using type- and const-generic associated types errors because bound types and constants aren't handled by trait solving. * The errors are technically non-fatal, but they happen in a [part of the compiler](https://github.com/rust-lang/rust/blob/4abb0ad2731e9ac6fd5d64d4cf15b7c82e4b5a81/src/librustc_typeck/lib.rs#L298) that fairly aggressively stops compiling on errors. closes #47206 closes #49362 closes #62521 closes #63300 closes #64755 closes #67089
2 parents 0a440b1 + e7b8bfe commit b50c3b7

File tree

77 files changed

+1183
-631
lines changed

Some content is hidden

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

77 files changed

+1183
-631
lines changed

src/librustc/infer/error_reporting/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,7 @@ impl<'tcx> ObligationCause<'tcx> {
19121912
use crate::traits::ObligationCauseCode::*;
19131913
match self.code {
19141914
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
1915+
CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
19151916
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) =>
19161917
Error0308(match source {
19171918
hir::MatchSource::IfLetDesugar { .. } =>
@@ -1948,6 +1949,7 @@ impl<'tcx> ObligationCause<'tcx> {
19481949
use crate::traits::ObligationCauseCode::*;
19491950
match self.code {
19501951
CompareImplMethodObligation { .. } => "method type is compatible with trait",
1952+
CompareImplTypeObligation { .. } => "associated type is compatible with trait",
19511953
ExprAssignable => "expression is assignable",
19521954
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
19531955
hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",

src/librustc/traits/error_reporting.rs

+8
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
702702
SelectionError::Unimplemented => {
703703
if let ObligationCauseCode::CompareImplMethodObligation {
704704
item_name, impl_item_def_id, trait_item_def_id,
705+
} | ObligationCauseCode::CompareImplTypeObligation {
706+
item_name, impl_item_def_id, trait_item_def_id,
705707
} = obligation.cause.code {
706708
self.report_extra_impl_obligation(
707709
span,
@@ -2631,6 +2633,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
26312633
but not on the corresponding trait method",
26322634
predicate));
26332635
}
2636+
ObligationCauseCode::CompareImplTypeObligation { .. } => {
2637+
err.note(&format!(
2638+
"the requirement `{}` appears on the associated impl type\
2639+
but not on the corresponding associated trait type",
2640+
predicate));
2641+
}
26342642
ObligationCauseCode::ReturnType |
26352643
ObligationCauseCode::ReturnValue(_) |
26362644
ObligationCauseCode::BlockTailExpression(_) => (),

src/librustc/traits/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,13 @@ pub enum ObligationCauseCode<'tcx> {
230230
trait_item_def_id: DefId,
231231
},
232232

233+
/// Error derived when matching traits/impls; see ObligationCause for more details
234+
CompareImplTypeObligation {
235+
item_name: ast::Name,
236+
impl_item_def_id: DefId,
237+
trait_item_def_id: DefId,
238+
},
239+
233240
/// Checking that this expression can be assigned where it needs to be
234241
// FIXME(eddyb) #11161 is the original Expr required?
235242
ExprAssignable,

src/librustc/traits/project.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::ty::subst::{Subst, InternalSubsts};
2323
use crate::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
2424
use crate::ty::fold::{TypeFoldable, TypeFolder};
2525
use crate::util::common::FN_OUTPUT_NAME;
26+
use syntax_pos::DUMMY_SP;
2627

2728
/// Depending on the stage of compilation, we want projection to be
2829
/// more or less conservative.
@@ -1437,11 +1438,14 @@ fn confirm_impl_candidate<'cx, 'tcx>(
14371438
obligation: &ProjectionTyObligation<'tcx>,
14381439
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>,
14391440
) -> Progress<'tcx> {
1441+
let tcx = selcx.tcx();
1442+
14401443
let VtableImplData { impl_def_id, substs, nested } = impl_vtable;
1444+
let assoc_item_id = obligation.predicate.item_def_id;
1445+
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
14411446

1442-
let tcx = selcx.tcx();
14431447
let param_env = obligation.param_env;
1444-
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_def_id);
1448+
let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id);
14451449

14461450
if !assoc_ty.item.defaultness.has_value() {
14471451
// This means that the impl is missing a definition for the
@@ -1456,16 +1460,28 @@ fn confirm_impl_candidate<'cx, 'tcx>(
14561460
obligations: nested,
14571461
};
14581462
}
1463+
let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
14591464
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
14601465
let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind {
14611466
let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
14621467
tcx.mk_opaque(assoc_ty.item.def_id, item_substs)
14631468
} else {
14641469
tcx.type_of(assoc_ty.item.def_id)
14651470
};
1466-
Progress {
1467-
ty: ty.subst(tcx, substs),
1468-
obligations: nested,
1471+
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
1472+
tcx.sess.delay_span_bug(
1473+
DUMMY_SP,
1474+
"impl item and trait item have different parameter counts",
1475+
);
1476+
Progress {
1477+
ty: tcx.types.err,
1478+
obligations: nested,
1479+
}
1480+
} else {
1481+
Progress {
1482+
ty: ty.subst(tcx, substs),
1483+
obligations: nested,
1484+
}
14691485
}
14701486
}
14711487

src/librustc/traits/structural_impls.rs

+9
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,15 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
514514
impl_item_def_id,
515515
trait_item_def_id,
516516
}),
517+
super::CompareImplTypeObligation {
518+
item_name,
519+
impl_item_def_id,
520+
trait_item_def_id,
521+
} => Some(super::CompareImplTypeObligation {
522+
item_name,
523+
impl_item_def_id,
524+
trait_item_def_id,
525+
}),
517526
super::ExprAssignable => Some(super::ExprAssignable),
518527
super::MatchExpressionArm(box super::MatchExpressionArmCause {
519528
arm_span,

src/librustc/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
13051305
}
13061306

13071307
#[inline]
1308-
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'_>) -> PolyTraitRef<'tcx> {
1308+
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
13091309
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
13101310
// `self.0.trait_ref` is permitted to have escaping regions.
13111311
// This is because here `self` has a `Binder` and so does our

src/librustc/ty/sty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1026,11 +1026,11 @@ impl<'tcx> ProjectionTy<'tcx> {
10261026
/// Extracts the underlying trait reference from this projection.
10271027
/// For example, if this is a projection of `<T as Iterator>::Item`,
10281028
/// then this function would return a `T: Iterator` trait reference.
1029-
pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::TraitRef<'tcx> {
1029+
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
10301030
let def_id = tcx.associated_item(self.item_def_id).container.id();
10311031
ty::TraitRef {
10321032
def_id,
1033-
substs: self.substs,
1033+
substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)),
10341034
}
10351035
}
10361036

src/librustc/ty/subst.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
234234
ty::GenericParamDefKind::Const => {
235235
tcx.mk_const(ty::Const {
236236
val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
237-
ty: tcx.type_of(def_id),
237+
ty: tcx.type_of(param.def_id),
238238
}).into()
239239
}
240240
}
@@ -533,8 +533,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
533533
data.name,
534534
self.root_ty,
535535
data.index);
536-
self.tcx.sess.delay_span_bug(span, &msg);
537-
r
536+
span_bug!(span, "{}", msg);
538537
}
539538
}
540539
}

src/librustc_resolve/late.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1119,17 +1119,16 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
11191119

11201120
visit::walk_impl_item(this, impl_item);
11211121
}
1122-
AssocItemKind::TyAlias(_, Some(ref ty)) => {
1122+
AssocItemKind::TyAlias(_, _) => {
11231123
// If this is a trait impl, ensure the type
11241124
// exists in trait
11251125
this.check_trait_item(impl_item.ident,
11261126
TypeNS,
11271127
impl_item.span,
11281128
|n, s| TypeNotMemberOfTrait(n, s));
11291129

1130-
this.visit_ty(ty);
1130+
visit::walk_impl_item(this, impl_item);
11311131
}
1132-
AssocItemKind::TyAlias(_, None) => {}
11331132
AssocItemKind::Macro(_) =>
11341133
panic!("unexpanded macro in resolve!"),
11351134
}

src/librustc_typeck/astconv.rs

+70-16
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub trait AstConv<'tcx> {
8888
fn projected_ty_from_poly_trait_ref(&self,
8989
span: Span,
9090
item_def_id: DefId,
91+
item_segment: &hir::PathSegment,
9192
poly_trait_ref: ty::PolyTraitRef<'tcx>)
9293
-> Ty<'tcx>;
9394

@@ -205,6 +206,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
205206
let (substs, assoc_bindings, _) = self.create_substs_for_ast_path(
206207
span,
207208
def_id,
209+
&[],
208210
item_segment.generic_args(),
209211
item_segment.infer_args,
210212
None,
@@ -615,9 +617,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
615617
/// `Output = u32` are returned in the `Vec<ConvertedBinding...>` result.
616618
///
617619
/// Note that the type listing given here is *exactly* what the user provided.
620+
///
621+
/// For (generic) associated types
622+
///
623+
/// ```
624+
/// <Vec<u8> as Iterable<u8>>::Iter::<'a>
625+
/// ```
626+
///
627+
/// We have the parent substs are the substs for the parent trait:
628+
/// `[Vec<u8>, u8]` and `generic_args` are the arguments for the associated
629+
/// type itself: `['a]`. The returned `SubstsRef` concatenates these two
630+
/// lists: `[Vec<u8>, u8, 'a]`.
618631
fn create_substs_for_ast_path<'a>(&self,
619632
span: Span,
620633
def_id: DefId,
634+
parent_substs: &[subst::GenericArg<'tcx>],
621635
generic_args: &'a hir::GenericArgs,
622636
infer_args: bool,
623637
self_ty: Option<Ty<'tcx>>)
@@ -633,17 +647,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
633647
let tcx = self.tcx();
634648
let generic_params = tcx.generics_of(def_id);
635649

636-
// If a self-type was declared, one should be provided.
637-
assert_eq!(generic_params.has_self, self_ty.is_some());
650+
if generic_params.has_self {
651+
if generic_params.parent.is_some() {
652+
// The parent is a trait so it should have at least one subst
653+
// for the `Self` type.
654+
assert!(!parent_substs.is_empty())
655+
} else {
656+
// This item (presumably a trait) needs a self-type.
657+
assert!(self_ty.is_some());
658+
}
659+
} else {
660+
assert!(self_ty.is_none() && parent_substs.is_empty());
661+
}
638662

639-
let has_self = generic_params.has_self;
640663
let (_, potential_assoc_types) = Self::check_generic_arg_count(
641664
tcx,
642665
span,
643666
&generic_params,
644667
&generic_args,
645668
GenericArgPosition::Type,
646-
has_self,
669+
self_ty.is_some(),
647670
infer_args,
648671
);
649672

@@ -652,7 +675,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
652675
});
653676
let default_needs_object_self = |param: &ty::GenericParamDef| {
654677
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
655-
if is_object && has_default && has_self {
678+
if is_object && has_default {
656679
let self_param = tcx.types.self_param;
657680
if tcx.at(span).type_of(param.def_id).walk().any(|ty| ty == self_param) {
658681
// There is no suitable inference default for a type parameter
@@ -668,7 +691,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
668691
let substs = Self::create_substs_for_generic_args(
669692
tcx,
670693
def_id,
671-
&[][..],
694+
parent_substs,
672695
self_ty.is_some(),
673696
self_ty,
674697
// Provide the generic args, and whether types should be inferred.
@@ -780,6 +803,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
780803
(substs, assoc_bindings, potential_assoc_types)
781804
}
782805

806+
crate fn create_substs_for_associated_item(
807+
&self,
808+
tcx: TyCtxt<'tcx>,
809+
span: Span,
810+
item_def_id: DefId,
811+
item_segment: &hir::PathSegment,
812+
parent_substs: SubstsRef<'tcx>,
813+
) -> SubstsRef<'tcx> {
814+
if tcx.generics_of(item_def_id).params.is_empty() {
815+
self.prohibit_generics(slice::from_ref(item_segment));
816+
817+
parent_substs
818+
} else {
819+
self.create_substs_for_ast_path(
820+
span,
821+
item_def_id,
822+
parent_substs,
823+
item_segment.generic_args(),
824+
item_segment.infer_args,
825+
None,
826+
).0
827+
}
828+
}
829+
783830
/// Instantiates the path for the given trait reference, assuming that it's
784831
/// bound to a valid trait type. Returns the `DefId` of the defining trait.
785832
/// The type _cannot_ be a type other than a trait type.
@@ -919,6 +966,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
919966

920967
self.create_substs_for_ast_path(span,
921968
trait_def_id,
969+
&[],
922970
trait_segment.generic_args(),
923971
trait_segment.infer_args,
924972
Some(self_ty))
@@ -1665,8 +1713,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16651713

16661714
debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
16671715

1668-
self.prohibit_generics(slice::from_ref(assoc_segment));
1669-
16701716
// Check if we have an enum variant.
16711717
let mut variant_resolution = None;
16721718
if let ty::Adt(adt_def, _) = qself_ty.kind {
@@ -1677,6 +1723,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16771723
if let Some(variant_def) = variant_def {
16781724
if permit_variants {
16791725
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span);
1726+
self.prohibit_generics(slice::from_ref(assoc_segment));
16801727
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
16811728
} else {
16821729
variant_resolution = Some(variant_def.def_id);
@@ -1767,7 +1814,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17671814
i.ident.modern() == assoc_ident
17681815
}).expect("missing associated type");
17691816

1770-
let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound);
1817+
let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
17711818
let ty = self.normalize_ty(span, ty);
17721819

17731820
let kind = DefKind::AssocTy;
@@ -1818,8 +1865,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
18181865

18191866
debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
18201867

1821-
self.prohibit_generics(slice::from_ref(item_segment));
1822-
18231868
let self_ty = if let Some(ty) = opt_self_ty {
18241869
ty
18251870
} else {
@@ -1861,9 +1906,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
18611906
self_ty,
18621907
trait_segment);
18631908

1909+
let item_substs = self.create_substs_for_associated_item(
1910+
tcx,
1911+
span,
1912+
item_def_id,
1913+
item_segment,
1914+
trait_ref.substs,
1915+
);
1916+
18641917
debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
18651918

1866-
self.normalize_ty(span, tcx.mk_projection(item_def_id, trait_ref.substs))
1919+
self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
18671920
}
18681921

18691922
pub fn prohibit_generics<'a, T: IntoIterator<Item = &'a hir::PathSegment>>(
@@ -2518,21 +2571,22 @@ impl<'tcx> Bounds<'tcx> {
25182571
// If it could be sized, and is, add the `Sized` predicate.
25192572
let sized_predicate = self.implicitly_sized.and_then(|span| {
25202573
tcx.lang_items().sized_trait().map(|sized| {
2521-
let trait_ref = ty::TraitRef {
2574+
let trait_ref = ty::Binder::bind(ty::TraitRef {
25222575
def_id: sized,
25232576
substs: tcx.mk_substs_trait(param_ty, &[])
2524-
};
2577+
});
25252578
(trait_ref.to_predicate(), span)
25262579
})
25272580
});
25282581

25292582
sized_predicate.into_iter().chain(
25302583
self.region_bounds.iter().map(|&(region_bound, span)| {
25312584
// Account for the binder being introduced below; no need to shift `param_ty`
2532-
// because, at present at least, it can only refer to early-bound regions.
2585+
// because, at present at least, it either only refers to early-bound regions,
2586+
// or it's a generic associated type that deliberately has escaping bound vars.
25332587
let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
25342588
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
2535-
(ty::Binder::dummy(outlives).to_predicate(), span)
2589+
(ty::Binder::bind(outlives).to_predicate(), span)
25362590
}).chain(
25372591
self.trait_bounds.iter().map(|&(bound_trait_ref, span)| {
25382592
(bound_trait_ref.to_predicate(), span)

0 commit comments

Comments
 (0)