Skip to content

Commit bde76b9

Browse files
committed
Auto merge of rust-lang#13264 - lowr:patch/no-dyn-without-trait, r=Veykril
Ensure at least one trait bound in `TyKind::DynTy` One would expect `TyKind::DynTy` to have at least one trait bound, but we may produce a dyn type with no trait bounds at all. This patch prevents it by returning `TyKind::Error` in such cases. An "empty" dyn type would have caused panic during method resolution without rust-lang#13257. Although already fixed, I think an invariant to never produce such types would help prevent similar problems in the future.
2 parents 4d989b5 + 9845e37 commit bde76b9

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

crates/hir-ty/src/chalk_ext.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ impl TyExt for Ty {
166166
let trait_ref = match self.kind(Interner) {
167167
// The principal trait bound should be the first element of the bounds. This is an
168168
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
169+
// FIXME: dyn types may not have principal trait and we don't want to return auto trait
170+
// here.
169171
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
170172
match b.skip_binders() {
171173
WhereClause::Implemented(trait_ref) => Some(trait_ref),

crates/hir-ty/src/lower.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -981,10 +981,11 @@ impl<'a> TyLoweringContext<'a> {
981981

982982
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
983983
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
984-
// INVARIANT: The principal trait bound must come first. Others may be in any order but
985-
// should be in the same order for the same set but possibly different order of bounds in
986-
// the input.
987-
// This invariant is used by `TyExt::dyn_trait()` and chalk.
984+
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
985+
// order but should be in the same order for the same set but possibly different order of
986+
// bounds in the input.
987+
// INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
988+
// These invariants are utilized by `TyExt::dyn_trait()` and chalk.
988989
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
989990
let mut bounds: Vec<_> = bounds
990991
.iter()
@@ -1035,6 +1036,12 @@ impl<'a> TyLoweringContext<'a> {
10351036
return None;
10361037
}
10371038

1039+
if bounds.first().and_then(|b| b.trait_id()).is_none() {
1040+
// When there's no trait bound, that's an error. This happens when the trait refs
1041+
// are unresolved.
1042+
return None;
1043+
}
1044+
10381045
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
10391046
// bounds. We shouldn't have repeated elements besides auto traits at this point.
10401047
bounds.dedup();
@@ -1046,7 +1053,8 @@ impl<'a> TyLoweringContext<'a> {
10461053
let bounds = crate::make_single_type_binders(bounds);
10471054
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
10481055
} else {
1049-
// FIXME: report error (additional non-auto traits or associated type rebound)
1056+
// FIXME: report error
1057+
// (additional non-auto traits, associated type rebound, or no resolved trait)
10501058
TyKind::Error.intern(Interner)
10511059
}
10521060
}

crates/hir-ty/src/tests/regression.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,3 +1691,15 @@ fn macrostmts() -> u8 {
16911691
"#,
16921692
);
16931693
}
1694+
1695+
#[test]
1696+
fn dyn_with_unresolved_trait() {
1697+
check_types(
1698+
r#"
1699+
fn foo(a: &dyn DoesNotExist) {
1700+
a.bar();
1701+
//^&{unknown}
1702+
}
1703+
"#,
1704+
);
1705+
}

0 commit comments

Comments
 (0)