Skip to content

Commit caac670

Browse files
authored
Rollup merge of #100247 - cjgillot:verify-dyn-trait-alias-defaults, r=lcnr
Generalize trait object generic param check to aliases. The current algorithm only checks that `Self` does not appear in defaults for traits. This is not sufficient for trait aliases. This PR moves the check to trait object elaboration, which sees through trait aliases. Fixes #82927. Fixes #84789.
2 parents 392ba5f + 0df84ae commit caac670

11 files changed

+178
-132
lines changed

compiler/rustc_typeck/src/astconv/mod.rs

+77-79
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use rustc_trait_selection::traits::error_reporting::{
4444
};
4545
use rustc_trait_selection::traits::wf::object_region_bounds;
4646

47-
use smallvec::SmallVec;
47+
use smallvec::{smallvec, SmallVec};
4848
use std::collections::BTreeSet;
4949
use std::slice;
5050

@@ -368,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
368368
return (tcx.intern_substs(&[]), arg_count);
369369
}
370370

371-
let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
372-
373371
struct SubstsForAstPathCtxt<'a, 'tcx> {
374372
astconv: &'a (dyn AstConv<'tcx> + 'a),
375373
def_id: DefId,
376374
generic_args: &'a GenericArgs<'a>,
377375
span: Span,
378-
missing_type_params: Vec<Symbol>,
379376
inferred_params: Vec<Span>,
380377
infer_args: bool,
381-
is_object: bool,
382-
}
383-
384-
impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
385-
fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
386-
let tcx = self.astconv.tcx();
387-
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
388-
if self.is_object && has_default {
389-
let default_ty = tcx.at(self.span).type_of(param.def_id);
390-
let self_param = tcx.types.self_param;
391-
if default_ty.walk().any(|arg| arg == self_param.into()) {
392-
// There is no suitable inference default for a type parameter
393-
// that references self, in an object type.
394-
return true;
395-
}
396-
}
397-
}
398-
399-
false
400-
}
401378
}
402379

403380
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
@@ -500,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
500477
GenericParamDefKind::Type { has_default, .. } => {
501478
if !infer_args && has_default {
502479
// No type parameter provided, but a default exists.
503-
504-
// If we are converting an object type, then the
505-
// `Self` parameter is unknown. However, some of the
506-
// other type parameters may reference `Self` in their
507-
// defaults. This will lead to an ICE if we are not
508-
// careful!
509-
if self.default_needs_object_self(param) {
510-
self.missing_type_params.push(param.name);
511-
tcx.ty_error().into()
512-
} else {
513-
// This is a default type parameter.
514-
let substs = substs.unwrap();
515-
if substs.iter().any(|arg| match arg.unpack() {
516-
GenericArgKind::Type(ty) => ty.references_error(),
517-
_ => false,
518-
}) {
519-
// Avoid ICE #86756 when type error recovery goes awry.
520-
return tcx.ty_error().into();
521-
}
522-
self.astconv
523-
.normalize_ty(
524-
self.span,
525-
EarlyBinder(tcx.at(self.span).type_of(param.def_id))
526-
.subst(tcx, substs),
527-
)
528-
.into()
480+
let substs = substs.unwrap();
481+
if substs.iter().any(|arg| match arg.unpack() {
482+
GenericArgKind::Type(ty) => ty.references_error(),
483+
_ => false,
484+
}) {
485+
// Avoid ICE #86756 when type error recovery goes awry.
486+
return tcx.ty_error().into();
529487
}
488+
self.astconv
489+
.normalize_ty(
490+
self.span,
491+
EarlyBinder(tcx.at(self.span).type_of(param.def_id))
492+
.subst(tcx, substs),
493+
)
494+
.into()
530495
} else if infer_args {
531-
// No type parameters were provided, we can infer all.
532-
let param = if !self.default_needs_object_self(param) {
533-
Some(param)
534-
} else {
535-
None
536-
};
537-
self.astconv.ty_infer(param, self.span).into()
496+
self.astconv.ty_infer(Some(param), self.span).into()
538497
} else {
539498
// We've already errored above about the mismatch.
540499
tcx.ty_error().into()
@@ -564,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
564523
def_id,
565524
span,
566525
generic_args,
567-
missing_type_params: vec![],
568526
inferred_params: vec![],
569527
infer_args,
570-
is_object,
571528
};
572529
let substs = Self::create_substs_for_generic_args(
573530
tcx,
@@ -579,13 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
579536
&mut substs_ctx,
580537
);
581538

582-
self.complain_about_missing_type_params(
583-
substs_ctx.missing_type_params,
584-
def_id,
585-
span,
586-
generic_args.args.is_empty(),
587-
);
588-
589539
debug!(
590540
"create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
591541
generics, self_ty, substs
@@ -1490,23 +1440,71 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14901440
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
14911441
let existential_trait_refs = regular_traits.iter().map(|i| {
14921442
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
1493-
if trait_ref.self_ty() != dummy_self {
1494-
// FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
1495-
// which picks up non-supertraits where clauses - but also, the object safety
1496-
// completely ignores trait aliases, which could be object safety hazards. We
1497-
// `delay_span_bug` here to avoid an ICE in stable even when the feature is
1498-
// disabled. (#66420)
1499-
tcx.sess.delay_span_bug(
1500-
DUMMY_SP,
1501-
&format!(
1502-
"trait_ref_to_existential called on {:?} with non-dummy Self",
1503-
trait_ref,
1504-
),
1443+
assert_eq!(trait_ref.self_ty(), dummy_self);
1444+
1445+
// Verify that `dummy_self` did not leak inside default type parameters. This
1446+
// could not be done at path creation, since we need to see through trait aliases.
1447+
let mut missing_type_params = vec![];
1448+
let mut references_self = false;
1449+
let generics = tcx.generics_of(trait_ref.def_id);
1450+
let substs: Vec<_> = trait_ref
1451+
.substs
1452+
.iter()
1453+
.enumerate()
1454+
.skip(1) // Remove `Self` for `ExistentialPredicate`.
1455+
.map(|(index, arg)| {
1456+
if let ty::GenericArgKind::Type(ty) = arg.unpack() {
1457+
debug!(?ty);
1458+
if ty == dummy_self {
1459+
let param = &generics.params[index];
1460+
missing_type_params.push(param.name);
1461+
tcx.ty_error().into()
1462+
} else if ty.walk().any(|arg| arg == dummy_self.into()) {
1463+
references_self = true;
1464+
tcx.ty_error().into()
1465+
} else {
1466+
arg
1467+
}
1468+
} else {
1469+
arg
1470+
}
1471+
})
1472+
.collect();
1473+
let substs = tcx.intern_substs(&substs[..]);
1474+
1475+
let span = i.bottom().1;
1476+
let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
1477+
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
1478+
&& hir_bound.span.contains(span)
1479+
});
1480+
self.complain_about_missing_type_params(
1481+
missing_type_params,
1482+
trait_ref.def_id,
1483+
span,
1484+
empty_generic_args,
1485+
);
1486+
1487+
if references_self {
1488+
let def_id = i.bottom().0.def_id();
1489+
let mut err = struct_span_err!(
1490+
tcx.sess,
1491+
i.bottom().1,
1492+
E0038,
1493+
"the {} `{}` cannot be made into an object",
1494+
tcx.def_kind(def_id).descr(def_id),
1495+
tcx.item_name(def_id),
1496+
);
1497+
err.note(
1498+
rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
1499+
.error_msg(),
15051500
);
1501+
err.emit();
15061502
}
1507-
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
1503+
1504+
ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs }
15081505
})
15091506
});
1507+
15101508
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
15111509
bound.map_bound(|b| {
15121510
if b.projection_ty.self_ty() != dummy_self {

src/test/ui/associated-types/issue-22560.stderr

+23-23
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,3 @@
1-
error[E0393]: the type parameter `Rhs` must be explicitly specified
2-
--> $DIR/issue-22560.rs:9:23
3-
|
4-
LL | trait Sub<Rhs=Self> {
5-
| ------------------- type parameter `Rhs` must be specified for this
6-
...
7-
LL | type Test = dyn Add + Sub;
8-
| ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
9-
|
10-
= note: because of the default `Self` reference, type parameters must be specified on object types
11-
12-
error[E0393]: the type parameter `Rhs` must be explicitly specified
13-
--> $DIR/issue-22560.rs:9:17
14-
|
15-
LL | trait Add<Rhs=Self> {
16-
| ------------------- type parameter `Rhs` must be specified for this
17-
...
18-
LL | type Test = dyn Add + Sub;
19-
| ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
20-
|
21-
= note: because of the default `Self` reference, type parameters must be specified on object types
22-
231
error[E0225]: only auto traits can be used as additional traits in a trait object
242
--> $DIR/issue-22560.rs:9:23
253
|
@@ -28,7 +6,7 @@ LL | type Test = dyn Add + Sub;
286
| |
297
| first non-auto trait
308
|
31-
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
9+
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
3210
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
3311

3412
error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
@@ -50,6 +28,28 @@ help: specify the associated types
5028
LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
5129
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
5230

31+
error[E0393]: the type parameter `Rhs` must be explicitly specified
32+
--> $DIR/issue-22560.rs:9:17
33+
|
34+
LL | trait Add<Rhs=Self> {
35+
| ------------------- type parameter `Rhs` must be specified for this
36+
...
37+
LL | type Test = dyn Add + Sub;
38+
| ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
39+
|
40+
= note: because of the default `Self` reference, type parameters must be specified on object types
41+
42+
error[E0393]: the type parameter `Rhs` must be explicitly specified
43+
--> $DIR/issue-22560.rs:9:23
44+
|
45+
LL | trait Sub<Rhs=Self> {
46+
| ------------------- type parameter `Rhs` must be specified for this
47+
...
48+
LL | type Test = dyn Add + Sub;
49+
| ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
50+
|
51+
= note: because of the default `Self` reference, type parameters must be specified on object types
52+
5353
error: aborting due to 4 previous errors
5454

5555
Some errors have detailed explanations: E0191, E0225, E0393.

src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
trait Foo<X = Box<dyn Foo>> {
55
//~^ ERROR cycle detected
6-
//~| ERROR cycle detected
76
}
87

98
fn main() { }

src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr

+1-20
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,11 @@ note: cycle used when collecting item types in top-level module
1010
|
1111
LL | / trait Foo<X = Box<dyn Foo>> {
1212
LL | |
13-
LL | |
14-
LL | | }
15-
LL | |
16-
LL | | fn main() { }
17-
| |_____________^
18-
19-
error[E0391]: cycle detected when computing type of `Foo::X`
20-
--> $DIR/cycle-trait-default-type-trait.rs:4:23
21-
|
22-
LL | trait Foo<X = Box<dyn Foo>> {
23-
| ^^^
24-
|
25-
= note: ...which immediately requires computing type of `Foo::X` again
26-
note: cycle used when collecting item types in top-level module
27-
--> $DIR/cycle-trait-default-type-trait.rs:4:1
28-
|
29-
LL | / trait Foo<X = Box<dyn Foo>> {
30-
LL | |
31-
LL | |
3213
LL | | }
3314
LL | |
3415
LL | | fn main() { }
3516
| |_____________^
3617

37-
error: aborting due to 2 previous errors
18+
error: aborting due to previous error
3819

3920
For more information about this error, try `rustc --explain E0391`.

src/test/ui/issues/issue-21950.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
2+
--> $DIR/issue-21950.rs:10:25
3+
|
4+
LL | type Output;
5+
| ----------- `Output` defined here
6+
...
7+
LL | let x = &10 as &dyn Add;
8+
| ^^^ help: specify the associated type: `Add<Output = Type>`
9+
110
error[E0393]: the type parameter `Rhs` must be explicitly specified
211
--> $DIR/issue-21950.rs:10:25
312
|
@@ -9,15 +18,6 @@ LL | let x = &10 as &dyn Add;
918
|
1019
= note: because of the default `Self` reference, type parameters must be specified on object types
1120

12-
error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
13-
--> $DIR/issue-21950.rs:10:25
14-
|
15-
LL | type Output;
16-
| ----------- `Output` defined here
17-
...
18-
LL | let x = &10 as &dyn Add;
19-
| ^^^ help: specify the associated type: `Add<Output = Type>`
20-
2121
error: aborting due to 2 previous errors
2222

2323
Some errors have detailed explanations: E0191, E0393.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait SendEqAlias<T> = PartialEq;
2+
//~^ ERROR trait aliases are experimental
3+
4+
struct Foo<T>(dyn SendEqAlias<T>);
5+
//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
6+
7+
struct Bar<T>(dyn SendEqAlias<T>, T);
8+
//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
9+
10+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0658]: trait aliases are experimental
2+
--> $DIR/generic-default-in-dyn.rs:1:1
3+
|
4+
LL | trait SendEqAlias<T> = PartialEq;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
8+
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
9+
10+
error[E0393]: the type parameter `Rhs` must be explicitly specified
11+
--> $DIR/generic-default-in-dyn.rs:4:19
12+
|
13+
LL | struct Foo<T>(dyn SendEqAlias<T>);
14+
| ^^^^^^^^^^^^^^ missing reference to `Rhs`
15+
|
16+
::: $SRC_DIR/core/src/cmp.rs:LL:COL
17+
|
18+
LL | pub trait PartialEq<Rhs: ?Sized = Self> {
19+
| --------------------------------------- type parameter `Rhs` must be specified for this
20+
|
21+
= note: because of the default `Self` reference, type parameters must be specified on object types
22+
23+
error[E0393]: the type parameter `Rhs` must be explicitly specified
24+
--> $DIR/generic-default-in-dyn.rs:7:19
25+
|
26+
LL | struct Bar<T>(dyn SendEqAlias<T>, T);
27+
| ^^^^^^^^^^^^^^ missing reference to `Rhs`
28+
|
29+
::: $SRC_DIR/core/src/cmp.rs:LL:COL
30+
|
31+
LL | pub trait PartialEq<Rhs: ?Sized = Self> {
32+
| --------------------------------------- type parameter `Rhs` must be specified for this
33+
|
34+
= note: because of the default `Self` reference, type parameters must be specified on object types
35+
36+
error: aborting due to 3 previous errors
37+
38+
Some errors have detailed explanations: E0393, E0658.
39+
For more information about an error, try `rustc --explain E0393`.

0 commit comments

Comments
 (0)