Skip to content

Commit 43e93d6

Browse files
committed
Normalize trait ref before orphan check
1 parent 1bc0463 commit 43e93d6

11 files changed

+202
-5
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

+48-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::traits::{
2222
};
2323
use rustc_data_structures::fx::FxIndexSet;
2424
use rustc_errors::Diagnostic;
25-
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
25+
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
2626
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
2727
use rustc_infer::traits::{util, TraitEngine};
2828
use rustc_middle::traits::query::NoSolution;
@@ -547,7 +547,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
547547
tcx: TyCtxt<'tcx>,
548548
trait_ref: ty::TraitRef<'tcx>,
549549
) -> bool {
550-
trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
550+
trait_ref.def_id.is_local() || tcx.has_attr(trait_ref.def_id, sym::fundamental)
551551
}
552552

553553
#[derive(Debug)]
@@ -564,7 +564,7 @@ pub enum OrphanCheckErr<'tcx> {
564564
/// 2. Some local type must appear in `Self`.
565565
#[instrument(level = "debug", skip(tcx), ret)]
566566
pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
567-
// We only except this routine to be invoked on implementations
567+
// We only accept this routine to be invoked on implementations
568568
// of a trait, not inherent implementations.
569569
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
570570
debug!(?trait_ref);
@@ -575,9 +575,54 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
575575
return Ok(());
576576
}
577577

578+
let trait_ref = normalize_trait_ref(tcx, trait_ref, impl_def_id);
579+
578580
orphan_check_trait_ref::<!>(trait_ref, InCrate::Local, |ty| Ok(ty)).unwrap()
579581
}
580582

583+
fn normalize_trait_ref<'tcx>(
584+
tcx: TyCtxt<'tcx>,
585+
trait_ref: ty::TraitRef<'tcx>,
586+
impl_def_id: DefId,
587+
) -> ty::TraitRef<'tcx> {
588+
let delay_bug = || {
589+
tcx.sess.delay_span_bug(
590+
tcx.def_span(impl_def_id),
591+
format!(
592+
"orphan check: failed to normalize `{trait_ref}` while checking {impl_def_id:?}"
593+
),
594+
)
595+
};
596+
597+
let infcx = tcx.infer_ctxt().build();
598+
let cause = ObligationCause::dummy();
599+
let param_env = tcx.param_env(impl_def_id);
600+
601+
if infcx.next_trait_solver() {
602+
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(&infcx);
603+
let args = trait_ref.args.iter().map(|arg| {
604+
if let ty::GenericArgKind::Type(ty) = arg.unpack()
605+
&& let ty::Alias(..) = ty.kind()
606+
{
607+
match infcx.at(&cause, param_env).structurally_normalize(ty, &mut *fulfill_cx) {
608+
Ok(ty) => ty,
609+
_ => Ty::new_error(tcx, delay_bug()),
610+
}.into()
611+
} else {
612+
arg
613+
}
614+
});
615+
ty::TraitRef::new(tcx, trait_ref.def_id, args)
616+
} else {
617+
let ocx = ObligationCtxt::new(&infcx);
618+
let trait_ref = ocx.normalize(&cause, param_env, trait_ref);
619+
if !ocx.select_all_or_error().is_empty() {
620+
delay_bug();
621+
}
622+
trait_ref
623+
}
624+
}
625+
581626
/// Checks whether a trait-ref is potentially implementable by a crate.
582627
///
583628
/// The current rule is that a trait-ref orphan checks in a crate C:

tests/ui/associated-types/issue-38821.rs

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub trait Column: Expression {}
2222

2323
#[derive(Debug, Copy, Clone)]
2424
//~^ ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
25+
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
26+
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
2527
pub enum ColumnInsertValue<Col, Expr> where
2628
Col: Column,
2729
Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,

tests/ui/associated-types/issue-38821.stderr

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
2+
--> $DIR/issue-38821.rs:23:10
3+
|
4+
LL | #[derive(Debug, Copy, Clone)]
5+
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
6+
|
7+
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
8+
--> $DIR/issue-38821.rs:9:18
9+
|
10+
LL | impl<T: NotNull> IntoNullable for T {
11+
| ------- ^^^^^^^^^^^^ ^
12+
| |
13+
| unsatisfied trait bound introduced here
14+
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
15+
help: consider further restricting the associated type
16+
|
17+
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
18+
| +++++++++++++++++++++++++++++++++++++++
19+
120
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
221
--> $DIR/issue-38821.rs:23:17
322
|
@@ -17,6 +36,25 @@ help: consider further restricting the associated type
1736
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
1837
| +++++++++++++++++++++++++++++++++++++++
1938

20-
error: aborting due to previous error
39+
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
40+
--> $DIR/issue-38821.rs:23:23
41+
|
42+
LL | #[derive(Debug, Copy, Clone)]
43+
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
44+
|
45+
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
46+
--> $DIR/issue-38821.rs:9:18
47+
|
48+
LL | impl<T: NotNull> IntoNullable for T {
49+
| ------- ^^^^^^^^^^^^ ^
50+
| |
51+
| unsatisfied trait bound introduced here
52+
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
53+
help: consider further restricting the associated type
54+
|
55+
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
56+
| +++++++++++++++++++++++++++++++++++++++
57+
58+
error: aborting due to 3 previous errors
2159

2260
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub trait Trait<T, U, V> {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-projections-dont-cover.rs:20:6
3+
|
4+
LL | impl<T> foreign::Trait<Local, T, ()> for <T as Identity>::Output {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
9+
10+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
11+
--> $DIR/orphan-check-projections-dont-cover.rs:23:6
12+
|
13+
LL | impl<T> foreign::Trait<<T as Identity>::Output, Local, T> for Option<T> {}
14+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
15+
|
16+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
17+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0210`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-projections-dont-cover.rs:20:6
3+
|
4+
LL | impl<T> foreign::Trait<Local, T, ()> for <T as Identity>::Output {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
9+
10+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
11+
--> $DIR/orphan-check-projections-dont-cover.rs:23:6
12+
|
13+
LL | impl<T> foreign::Trait<<T as Identity>::Output, Local, T> for Option<T> {}
14+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
15+
|
16+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
17+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0210`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Regression test for issue #99554.
2+
// Don't consider projections to cover type parameters.
3+
4+
// revisions: classic next
5+
//[next] -Ztrait-solver=next
6+
7+
// aux-crate:foreign=parametrized-trait.rs
8+
// edition:2021
9+
10+
trait Identity {
11+
type Output;
12+
}
13+
14+
impl<T> Identity for T {
15+
type Output = T;
16+
}
17+
18+
struct Local;
19+
20+
impl<T> foreign::Trait<Local, T, ()> for <T as Identity>::Output {}
21+
//~^ ERROR type parameter `T` must be covered by another type
22+
23+
impl<T> foreign::Trait<<T as Identity>::Output, Local, T> for Option<T> {}
24+
//~^ ERROR type parameter `T` must be covered by another type
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-weak-aliases-dont-cover.rs:16:6
3+
|
4+
LL | impl<T> foreign::Trait<Local, T, ()> for Identity<T> {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0210`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-weak-aliases-dont-cover.rs:16:6
3+
|
4+
LL | impl<T> foreign::Trait<Local, T, ()> for Identity<T> {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0210`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Don't consider weak aliases to cover type parameters.
2+
3+
// revisions: classic next
4+
//[next] -Ztrait-solver=next
5+
6+
// aux-crate:foreign=parametrized-trait.rs
7+
// edition:2021
8+
9+
#![feature(lazy_type_alias)]
10+
#![allow(incomplete_features)]
11+
12+
type Identity<T> = T;
13+
14+
struct Local;
15+
16+
impl<T> foreign::Trait<Local, T, ()> for Identity<T> {}
17+
//~^ ERROR type parameter `T` must be covered by another type
18+
19+
fn main() {}

tests/ui/type-alias-impl-trait/coherence.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar
44
LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------
66
| | |
7-
| | `AliasOfForeignType<()>` is not defined in the current crate
7+
| | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
88
| impl doesn't use only types from inside the current crate
99
|
1010
= note: define and implement a trait or new type instead

0 commit comments

Comments
 (0)