Skip to content
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

Improve spans of non-WF implied bound types #106582

Merged
merged 3 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Improve spans of non-WF implied bound types
  • Loading branch information
compiler-errors committed Jan 8, 2023
commit ca554efaf78962f9dc9599663b29626269c69c8c
58 changes: 21 additions & 37 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1489,54 +1489,38 @@ fn check_fn_or_method<'tcx>(
def_id: LocalDefId,
) {
let tcx = wfcx.tcx();
let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);

// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
// for each type, preventing the HIR wf check from generating
// a nice error message.
let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig;
inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| {
wfcx.normalize(
span,
Some(WellFormedLoc::Param {
function: def_id,
// Note that the `param_idx` of the output type is
// one greater than the index of the last input type.
param_idx: i.try_into().unwrap(),
}),
ty,
)
}));
// Manually call `normalize_associated_types_in` on the other types
// in `FnSig`. This ensures that if the types of these fields
// ever change to include projections, we will start normalizing
// them automatically.
let sig = ty::FnSig {
inputs_and_output,
c_variadic: wfcx.normalize(span, None, c_variadic),
unsafety: wfcx.normalize(span, None, unsafety),
abi: wfcx.normalize(span, None, abi),
};
let arg_span =
|idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span);

sig.inputs_and_output =
tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
wfcx.normalize(
arg_span(idx),
Some(WellFormedLoc::Param {
function: def_id,
// Note that the `param_idx` of the output type is
// one greater than the index of the last input type.
param_idx: idx.try_into().unwrap(),
}),
ty,
)
}));

for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() {
for (idx, ty) in sig.inputs_and_output.iter().enumerate() {
wfcx.register_wf_obligation(
ty.span,
Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
input_ty.into(),
arg_span(idx),
Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }),
ty.into(),
);
}

wfcx.register_wf_obligation(
hir_decl.output.span(),
Some(WellFormedLoc::Param {
function: def_id,
param_idx: sig.inputs().len().try_into().unwrap(),
}),
sig.output().into(),
);

check_where_clauses(wfcx, span, def_id);

check_return_position_impl_trait_in_trait_bounds(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ rustc_queries! {
///
/// Note that we've liberated the late bound regions of function signatures, so
/// this can not be used to check whether these types are well formed.
query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
query assumed_wf_types(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] {
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_trait_selection/src/traits/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
let assumed_wf_types = tcx.assumed_wf_types(def_id);
let mut implied_bounds = FxIndexSet::default();
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let cause = ObligationCause::misc(span, hir_id);
for ty in assumed_wf_types {
for &(ty, ty_span) in assumed_wf_types {
let span = if ty_span.is_dummy() { span } else { ty_span };
// FIXME(@lcnr): rustc currently does not check wf for types
// pre-normalization, meaning that implied bounds are sometimes
// incorrect. See #100910 for more details.
Expand All @@ -205,7 +205,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
// sound and then uncomment this line again.

// implied_bounds.insert(ty);
let normalized = self.normalize(&cause, param_env, ty);
let normalized = self.normalize(&ObligationCause::misc(span, hir_id), param_env, ty);
implied_bounds.insert(normalized);
}
implied_bounds
Expand Down
67 changes: 57 additions & 10 deletions compiler/rustc_ty_utils/src/implied_bounds.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,80 @@
use crate::rustc_middle::ty::DefIdTree;
use rustc_hir::{def::DefKind, def_id::DefId};
use rustc_hir::{self as hir, def::DefKind, def_id::DefId};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::{Span, DUMMY_SP};

pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { assumed_wf_types, ..*providers };
}

fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &[(Ty<'_>, Span)] {
match tcx.def_kind(def_id) {
DefKind::Fn => {
let sig = tcx.fn_sig(def_id);
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
liberated_sig.inputs_and_output
if let Some(node) = tcx.hir().get_if_local(def_id)
&& let Some(decl) = node.fn_decl()
{
assert_eq!(decl.inputs.len(), liberated_sig.inputs().len());
tcx.arena.alloc_from_iter(std::iter::zip(
liberated_sig.inputs_and_output,
decl.inputs.iter().map(|ty| ty.span).chain([decl.output.span()]),
))
} else {
tcx.arena.alloc_from_iter(
liberated_sig.inputs_and_output.iter().map(|ty| (ty, DUMMY_SP)),
)
}
}
DefKind::AssocFn => {
let sig = tcx.fn_sig(def_id);
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
let mut assumed_wf_types: Vec<_> =
tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
assumed_wf_types.extend(liberated_sig.inputs_and_output);
tcx.intern_type_list(&assumed_wf_types)
let assumed_wf_types = tcx.assumed_wf_types(tcx.parent(def_id));
if let Some(node) = tcx.hir().get_if_local(def_id)
&& let Some(decl) = node.fn_decl()
{
assert_eq!(decl.inputs.len(), liberated_sig.inputs().len());
tcx.arena.alloc_from_iter(assumed_wf_types.iter().copied().chain(std::iter::zip(
liberated_sig.inputs_and_output,
decl.inputs.iter().map(|ty| ty.span).chain([decl.output.span()]),
)))
} else {
tcx.arena.alloc_from_iter(assumed_wf_types.iter().copied().chain(
liberated_sig.inputs_and_output.iter().map(|ty| (ty, DUMMY_SP)),
))
}
}
DefKind::Impl => match tcx.impl_trait_ref(def_id) {
Some(trait_ref) => {
let types: Vec<_> = trait_ref.substs.types().collect();
tcx.intern_type_list(&types)
let self_span = if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(impl_),
..
})) = tcx.hir().get_if_local(def_id)
{
impl_.self_ty.span
} else {
DUMMY_SP
};
tcx.arena.alloc_from_iter(std::iter::zip(
types,
// FIXME: reliable way of getting trait ref substs...
[self_span].into_iter().chain(std::iter::repeat(DUMMY_SP)),
))
}
// Only the impl self type
None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
None => {
let span = if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(impl_),
..
})) = tcx.hir().get_if_local(def_id)
{
impl_.self_ty.span
} else {
DUMMY_SP
};
tcx.arena.alloc_from_iter([(tcx.type_of(def_id), span)])
}
},
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
DefKind::Mod
Expand Down Expand Up @@ -56,6 +103,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator => ty::List::empty(),
| DefKind::Generator => &[],
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-for-unimpl-trait.rs:10:5
--> $DIR/associated-types-for-unimpl-trait.rs:10:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: Get` is not satisfied
--> $DIR/associated-types-no-suitable-bound.rs:11:5
--> $DIR/associated-types-no-suitable-bound.rs:11:21
|
LL | fn uhoh<T>(foo: <T as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
| ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
error[E0277]: the trait bound `(T, U): Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait.rs:22:5
--> $DIR/associated-types-no-suitable-supertrait.rs:22:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`

error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait.rs:17:5
--> $DIR/associated-types-no-suitable-supertrait.rs:17:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
|
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/associated-types/issue-59324.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
{
fn get_service(
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
//~| ERROR the trait bound `Bug: Foo` is not satisfied
&self,
) -> Self::AssocType;
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
}

fn with_factory<H>(factory: dyn ThriftService<()>) {}
Expand Down
17 changes: 6 additions & 11 deletions src/test/ui/associated-types/issue-59324.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ LL | |
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
LL | | ) -> Self::AssocType;
LL | |
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
Expand All @@ -34,7 +34,6 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
|
LL | / fn get_service(
LL | |
LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
Expand All @@ -45,20 +44,16 @@ LL | pub trait ThriftService<Bug: NotFoo + Foo>:
| +++++

error[E0277]: the trait bound `(): Foo` is not satisfied
--> $DIR/issue-59324.rs:23:1
--> $DIR/issue-59324.rs:23:29
|
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`

error[E0277]: the trait bound `Bug: Foo` is not satisfied
--> $DIR/issue-59324.rs:16:5
--> $DIR/issue-59324.rs:19:10
|
LL | / fn get_service(
LL | |
LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
LL | ) -> Self::AssocType;
| ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
|
help: consider further restricting this bound
|
Expand Down
8 changes: 3 additions & 5 deletions src/test/ui/issues/issue-18611.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
error[E0277]: the trait bound `isize: HasState` is not satisfied
--> $DIR/issue-18611.rs:1:1
--> $DIR/issue-18611.rs:1:18
|
LL | / fn add_state(op: <isize as HasState>::State) {
LL | |
LL | | }
| |_^ the trait `HasState` is not implemented for `isize`
LL | fn add_state(op: <isize as HasState>::State) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`

error: aborting due to previous error

Expand Down
24 changes: 6 additions & 18 deletions src/test/ui/issues/issue-20831-debruijn.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/issue-20831-debruijn.rs:28:5
--> $DIR/issue-20831-debruijn.rs:28:33
|
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
LL | | // Not obvious, but there is an implicit lifetime here -------^
LL | |
LL | | //
... |
LL | | self.sub = t;
LL | | }
| |_____^
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> $DIR/issue-20831-debruijn.rs:28:58
Expand All @@ -21,16 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined he
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
| ^^
note: ...so that the types are compatible
--> $DIR/issue-20831-debruijn.rs:28:5
--> $DIR/issue-20831-debruijn.rs:28:33
|
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
LL | | // Not obvious, but there is an implicit lifetime here -------^
LL | |
LL | | //
... |
LL | | self.sub = t;
LL | | }
| |_____^
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `<MyStruct<'a> as Publisher<'_>>`
found `<MyStruct<'_> as Publisher<'_>>`

Expand Down
1 change: 0 additions & 1 deletion src/test/ui/issues/issue-35570.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ trait Trait2<'a> {

fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
//~^ ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
//~| ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
let _e: (usize, usize) = unsafe{mem::transmute(param)};
}

Expand Down
Loading