Skip to content

Commit

Permalink
Taint projection selection in the presence of unconstrained parameter…
Browse files Browse the repository at this point in the history
…s on selected impls
  • Loading branch information
oli-obk committed Jul 22, 2024
1 parent dbbcbf9 commit 61cec80
Show file tree
Hide file tree
Showing 21 changed files with 128 additions and 221 deletions.
8 changes: 7 additions & 1 deletion compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::ty::GenericArgsRef;
use crate::ty::{self, AdtKind, Ty};

use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
Expand Down Expand Up @@ -572,6 +572,12 @@ pub enum SelectionError<'tcx> {
ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> },
}

impl From<ErrorGuaranteed> for SelectionError<'_> {
fn from(guar: ErrorGuaranteed) -> Self {
Self::Overflow(guar.into())
}
}

#[derive(Clone, Debug, TypeVisitable)]
pub struct SignatureMismatchData<'tcx> {
pub found_trait_ref: ty::TraitRef<'tcx>,
Expand Down
27 changes: 14 additions & 13 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use rustc_middle::ty::{
};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use rustc_span::ErrorGuaranteed;

use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type};
Expand Down Expand Up @@ -61,7 +62,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

ImplCandidate(impl_def_id) => {
ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))
ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)?)
}

AutoImplCandidate => {
Expand Down Expand Up @@ -116,7 +117,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

TraitAliasCandidate => {
let data = self.confirm_trait_alias_candidate(obligation);
let data = self.confirm_trait_alias_candidate(obligation)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}

Expand Down Expand Up @@ -421,7 +422,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
let types = self.constituent_types_for_ty(self_ty)?;
Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types))
Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)?)
}

/// See `confirm_auto_impl_candidate`.
Expand All @@ -430,21 +431,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
trait_def_id: DefId,
nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
) -> Vec<PredicateObligation<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, ErrorGuaranteed> {
debug!(?nested, "vtable_auto_impl");
ensure_sufficient_stack(|| {
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);

let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
let trait_obligations = self.impl_or_trait_obligations(
&cause,
obligation.recursion_depth + 1,
obligation.param_env,
trait_def_id,
trait_ref.args,
obligation.predicate,
);
)?;

let mut obligations = self.collect_predicates_for_types(
obligation.param_env,
Expand All @@ -460,15 +461,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

debug!(?obligations, "vtable_auto_impl");

obligations
Ok(obligations)
})
}

fn confirm_impl_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
impl_def_id: DefId,
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
) -> Result<ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, ErrorGuaranteed> {
debug!(?obligation, ?impl_def_id, "confirm_impl_candidate");

// First, create the generic parameters by matching the impl again,
Expand All @@ -495,7 +496,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
) -> Result<ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, ErrorGuaranteed> {
debug!(?impl_def_id, ?args, ?recursion_depth, "vtable_impl");

let mut impl_obligations = self.impl_or_trait_obligations(
Expand All @@ -505,7 +506,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
impl_def_id,
args.value,
parent_trait_pred,
);
)?;

debug!(?impl_obligations, "vtable_impl");

Expand All @@ -516,7 +517,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
impl_obligations.extend(args.obligations);

ImplSourceUserDefinedData { impl_def_id, args: args.value, nested: impl_obligations }
Ok(ImplSourceUserDefinedData { impl_def_id, args: args.value, nested: impl_obligations })
}

fn confirm_object_candidate(
Expand Down Expand Up @@ -737,7 +738,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_trait_alias_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, ErrorGuaranteed> {
debug!(?obligation, "confirm_trait_alias_candidate");

let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
Expand Down Expand Up @@ -1377,7 +1378,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
new_obligation.param_env,
obligation.predicate,
)
});
})?;
nested.extend(obligations.nested);
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast};
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_span::symbol::sym;
use rustc_span::ErrorGuaranteed;
use rustc_span::Symbol;

use std::cell::{Cell, RefCell};
Expand Down Expand Up @@ -2737,7 +2738,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
def_id: DefId, // of impl or trait
args: GenericArgsRef<'tcx>, // for impl or trait
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
) -> Vec<PredicateObligation<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, ErrorGuaranteed> {
let tcx = self.tcx();

// To allow for one-pass evaluation of the nested obligation,
Expand All @@ -2755,6 +2756,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// `$1: Copy`, so we must ensure the obligations are emitted in
// that order.
let predicates = tcx.predicates_of(def_id);
predicates.tainted_by_errors?;
assert_eq!(predicates.parent, None);
let predicates = predicates.instantiate_own(tcx, args);
let mut obligations = Vec::with_capacity(predicates.len());
Expand Down Expand Up @@ -2787,7 +2789,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
});
}

obligations
Ok(obligations)
}
}

Expand Down
23 changes: 0 additions & 23 deletions tests/crashes/123141.rs

This file was deleted.

22 changes: 0 additions & 22 deletions tests/crashes/125874.rs

This file was deleted.

11 changes: 0 additions & 11 deletions tests/crashes/126942.rs

This file was deleted.

18 changes: 18 additions & 0 deletions tests/ui/associated-item/unconstrained_impl_param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! This test used to ICE during the normalization of
//! `I`'s type, because of the mismatch of generic parameters
//! on the impl with the generic parameters the projection can
//! fulfill.
struct Thing;

pub trait Every {
type Assoc;
}
impl<T: ?Sized> Every for Thing {
//~^ ERROR: `T` is not constrained
type Assoc = T;
}

static I: <Thing as Every>::Assoc = 3;

fn main() {}
9 changes: 9 additions & 0 deletions tests/ui/associated-item/unconstrained_impl_param.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained_impl_param.rs:11:6
|
LL | impl<T: ?Sized> Every for Thing {
| ^ unconstrained type parameter

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0207`.
78 changes: 16 additions & 62 deletions tests/ui/generic-associated-types/bugs/issue-87735.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,73 +22,27 @@ help: consider adding an explicit lifetime bound
LL | type Output<'a> = FooRef<'a, U> where Self: 'a, U: 'a;
| +++++++

error[E0309]: the parameter type `T` may not live long enough
--> $DIR/issue-87735.rs:31:15
error[E0599]: no method named `as_ref2` found for struct `Foo` in the current scope
--> $DIR/issue-87735.rs:43:14
|
LL | impl<'b, T, U> AsRef2 for Foo<T>
| -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
...
LL | T: AsRef2<Output<'b> = &'b [U]>,
| ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
note: ...that is required by this bound
--> $DIR/issue-87735.rs:7:31
|
LL | type Output<'a> where Self: 'a;
| ^^
help: consider adding an explicit lifetime bound
|
LL | T: AsRef2<Output<'b> = &'b [U]> + 'b,
| ++++

error[E0309]: the parameter type `T` may not live long enough
--> $DIR/issue-87735.rs:36:31
|
LL | impl<'b, T, U> AsRef2 for Foo<T>
| -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
LL | struct Foo<T>(T);
| ------------- method `as_ref2` not found for this struct
...
LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
| ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
LL | dbg!(foo.as_ref2());
| ^^^^^^^ method not found in `Foo<Vec<{integer}>>`
|
note: ...that is required by this bound
--> $DIR/issue-87735.rs:7:31
= help: items from traits can only be used if the trait is implemented and in scope
note: `AsRef2` defines an item `as_ref2`, perhaps you need to implement it
--> $DIR/issue-87735.rs:6:1
|
LL | type Output<'a> where Self: 'a;
| ^^
help: consider adding an explicit lifetime bound
LL | pub trait AsRef2 {
| ^^^^^^^^^^^^^^^^
help: one of the expressions' fields has a method of the same name
|
LL | T: AsRef2<Output<'b> = &'b [U]> + 'b,
| ++++

error: lifetime may not live long enough
--> $DIR/issue-87735.rs:37:5
|
LL | impl<'b, T, U> AsRef2 for Foo<T>
| -- lifetime `'b` defined here
...
LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
| -- lifetime `'a` defined here
LL | FooRef(self.0.as_ref2())
| ^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`

error: lifetime may not live long enough
--> $DIR/issue-87735.rs:37:12
|
LL | impl<'b, T, U> AsRef2 for Foo<T>
| -- lifetime `'b` defined here
...
LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
| -- lifetime `'a` defined here
LL | FooRef(self.0.as_ref2())
| ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`

help: `'b` and `'a` must be the same: replace one with the other
LL | dbg!(foo.0.as_ref2());
| ++

error: aborting due to 6 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0207, E0309.
Some errors have detailed explanations: E0207, E0309, E0599.
For more information about an error, try `rustc --explain E0207`.
1 change: 0 additions & 1 deletion tests/ui/impl-trait/in-trait/refine-resolution-errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ impl<T: ?Sized> Mirror for () {

pub trait First {
async fn first() -> <() as Mirror>::Assoc;
//~^ ERROR type annotations needed
}

impl First for () {
Expand Down
11 changes: 2 additions & 9 deletions tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
LL | impl<T: ?Sized> Mirror for () {
| ^ unconstrained type parameter

error[E0282]: type annotations needed
--> $DIR/refine-resolution-errors.rs:15:5
|
LL | async fn first() -> <() as Mirror>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0207, E0282.
For more information about an error, try `rustc --explain E0207`.
For more information about this error, try `rustc --explain E0207`.
2 changes: 0 additions & 2 deletions tests/ui/impl-trait/issues/issue-87340.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ impl<T> X for () {
//~^ ERROR `T` is not constrained by the impl trait, self type, or predicates
type I = impl Sized;
fn f() -> Self::I {}
//~^ ERROR type annotations needed
//~| ERROR type annotations needed
}

fn main() {}
Loading

0 comments on commit 61cec80

Please sign in to comment.