-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle projections as uncovered types during coherence check #100555
Changes from all commits
56c2886
e6bf058
1ac08d8
7913a81
42347b8
d89dc3f
9f7b8dd
ca4711f
344e225
c3e2567
84e8ac2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,7 +111,7 @@ fn do_orphan_check_impl<'tcx>( | |
tr.path.span, | ||
trait_ref.self_ty(), | ||
impl_.self_ty.span, | ||
&impl_.generics, | ||
&impl_.of_trait.as_ref().unwrap().path.segments.last().unwrap().args().args, | ||
err, | ||
)?, | ||
} | ||
|
@@ -212,7 +212,7 @@ fn emit_orphan_check_error<'tcx>( | |
trait_span: Span, | ||
self_ty: Ty<'tcx>, | ||
self_ty_span: Span, | ||
generics: &hir::Generics<'tcx>, | ||
generics: &[rustc_hir::GenericArg<'tcx>], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
err: traits::OrphanCheckErr<'tcx>, | ||
) -> Result<!, ErrorGuaranteed> { | ||
Err(match err { | ||
|
@@ -275,59 +275,84 @@ fn emit_orphan_check_error<'tcx>( | |
err.note("define and implement a trait or new type instead"); | ||
err.emit() | ||
} | ||
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { | ||
let mut sp = sp; | ||
for param in generics.params { | ||
if param.name.ident().to_string() == param_ty.to_string() { | ||
sp = param.span; | ||
traits::OrphanCheckErr::UncoveredTy(param_ty, idx, local_type) => { | ||
let sp; | ||
let mut param_ty_in_fundamental_ty = false; | ||
|
||
match idx { | ||
0 => { | ||
sp = self_ty_span; | ||
atsuzaki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
match *self_ty.kind() { | ||
ty::Ref(..) => { | ||
param_ty_in_fundamental_ty = true; | ||
} | ||
ty::Adt(def, _) => { | ||
param_ty_in_fundamental_ty = def.is_fundamental(); | ||
} | ||
_ => (), | ||
} | ||
Comment on lines
+285
to
+293
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are you only doing that if the uncovered ty is in the self type? you can also have |
||
} | ||
_ => sp = generics[idx - 1].span(), | ||
} | ||
|
||
let message = match *param_ty.kind() { | ||
ty::Projection(..) => "associated type", | ||
_ => "type parameter", | ||
}; | ||
|
||
let fundamental_ty_msg = | ||
if param_ty_in_fundamental_ty { "as argument to a fundamental type " } else { "" }; | ||
|
||
match local_type { | ||
Some(local_type) => struct_span_err!( | ||
tcx.sess, | ||
sp, | ||
E0210, | ||
"type parameter `{}` must be covered by another type \ | ||
"{} `{}` {}must be covered by another type \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is existing, but these messages would probably be a lot clearer if we used inline format args, i.e.
(renaming |
||
when it appears before the first local type (`{}`)", | ||
message, | ||
param_ty, | ||
fundamental_ty_msg, | ||
local_type | ||
) | ||
.span_label( | ||
sp, | ||
format!( | ||
"type parameter `{}` must be covered by another type \ | ||
when it appears before the first local type (`{}`)", | ||
param_ty, local_type | ||
"{} `{}` {}must be covered by another type \ | ||
when it appears before the first local type (`{}`)", | ||
message, param_ty, fundamental_ty_msg, local_type | ||
), | ||
) | ||
.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", | ||
and no uncovered type parameters or associated types appear \ | ||
before that first local type", | ||
) | ||
.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", | ||
) | ||
.emit(), | ||
|
||
None => struct_span_err!( | ||
atsuzaki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tcx.sess, | ||
sp, | ||
E0210, | ||
"type parameter `{}` must be used as the type parameter for some \ | ||
"{} `{}` {}must be used as the type parameter for some \ | ||
local type (e.g., `MyStruct<{}>`)", | ||
message, | ||
param_ty, | ||
fundamental_ty_msg, | ||
param_ty | ||
) | ||
.span_label( | ||
sp, | ||
format!( | ||
"type parameter `{}` must be used as the type parameter for some \ | ||
local type", | ||
param_ty, | ||
"{} `{}` {}must be used as the type parameter for some \ | ||
local type", | ||
message, param_ty, fundamental_ty_msg | ||
), | ||
) | ||
.note( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub trait Foreign<T, U> { | ||
type Assoc; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Here we expect that orphan rule is violated | ||
// because T is an uncovered parameter appearing | ||
// before the first local (Issue #99554) | ||
|
||
// aux-build:coherence_projection_assoc.rs | ||
|
||
extern crate coherence_projection_assoc as lib; | ||
use lib::Foreign; | ||
|
||
trait Id { | ||
type Assoc; | ||
} | ||
|
||
impl<T> Id for T { | ||
type Assoc = T; | ||
} | ||
|
||
pub struct B; | ||
impl<T> Foreign<B, T> for <Vec<Vec<T>> as Id>::Assoc { | ||
//~^ ERROR E0210 | ||
type Assoc = usize; | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
error[E0210]: associated type `<Vec<Vec<T>> as Id>::Assoc` must be covered by another type when it appears before the first local type (`B`) | ||
--> $DIR/coherence-projection-uncovered-ty-2.rs:19:27 | ||
| | ||
LL | impl<T> Foreign<B, T> for <Vec<Vec<T>> as Id>::Assoc { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `<Vec<Vec<T>> as Id>::Assoc` must be covered by another type when it appears before the first local type (`B`) | ||
| | ||
= 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 or associated types appear before that first local type | ||
= 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 | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0210`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// aux-build:coherence_projection_assoc.rs | ||
|
||
extern crate coherence_projection_assoc as lib; | ||
use lib::Foreign; | ||
|
||
trait Id { | ||
type Assoc; | ||
} | ||
|
||
impl<T> Id for T { | ||
type Assoc = T; | ||
} | ||
|
||
pub struct Local<T>(T); | ||
impl<T> Foreign<<T as Id>::Assoc, Local<T>> for () { | ||
//~^ ERROR E0210 | ||
type Assoc = usize; | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
error[E0210]: associated type `<T as Id>::Assoc` must be covered by another type when it appears before the first local type (`Local<T>`) | ||
--> $DIR/coherence-projection-uncovered-ty-3.rs:15:17 | ||
| | ||
LL | impl<T> Foreign<<T as Id>::Assoc, Local<T>> for () { | ||
| ^^^^^^^^^^^^^^^^ associated type `<T as Id>::Assoc` must be covered by another type when it appears before the first local type (`Local<T>`) | ||
| | ||
= 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 or associated types appear before that first local type | ||
= 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 | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0210`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// aux-build:coherence_projection_assoc.rs | ||
|
||
extern crate coherence_projection_assoc as lib; | ||
use lib::Foreign; | ||
|
||
trait Id { | ||
type Assoc; | ||
} | ||
|
||
impl<T> Id for T { | ||
type Assoc = T; | ||
} | ||
|
||
impl<T> Foreign<(), Vec<T>> for <T as Id>::Assoc { | ||
//~^ ERROR E0210 | ||
type Assoc = usize; | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
error[E0210]: associated type `<T as Id>::Assoc` must be used as the type parameter for some local type (e.g., `MyStruct<<T as Id>::Assoc>`) | ||
--> $DIR/coherence-projection-uncovered-ty-4.rs:14:33 | ||
| | ||
LL | impl<T> Foreign<(), Vec<T>> for <T as Id>::Assoc { | ||
| ^^^^^^^^^^^^^^^^ associated type `<T as Id>::Assoc` must be used as the type parameter for some local type | ||
| | ||
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local | ||
= note: only traits defined in the current crate can be implemented for a type parameter | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0210`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Here we expect that orphan rule is violated | ||
// because T is an uncovered parameter appearing | ||
// before the first local (Issue #99554) | ||
|
||
// aux-build:coherence_projection_assoc.rs | ||
|
||
extern crate coherence_projection_assoc as lib; | ||
use lib::Foreign; | ||
|
||
trait Id { | ||
type Assoc; | ||
} | ||
|
||
impl<T> Id for T { | ||
type Assoc = T; | ||
} | ||
|
||
pub struct B; | ||
impl<T> Foreign<B, T> for <T as Id>::Assoc { | ||
//~^ ERROR E0210 | ||
type Assoc = usize; | ||
} | ||
|
||
fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should get the whole
substs
for the impl header, not just theself_ty
. With this you can check for fundamental types for all arguments.Alternatively, do the "is in fundamental" check, in
orphan_check_trait_ref
as part of theOrphanChecker
. That's probably a bit cleaner than computing it here