Skip to content

Commit

Permalink
Rollup merge of rust-lang#108557 - Nathan-Fenner:nathanf/adjust-error…
Browse files Browse the repository at this point in the history
…-span-fix-Some, r=WaffleLapkin

Point error span at Some constructor argument when trait resolution fails

This is a follow up to rust-lang#108254 and rust-lang#106477 which extends error span refinement to handle a case which I mistakenly believed was handled in rust-lang#106477. The goal is to refine the error span depicted below:

```rs
trait Fancy {}
impl <T> Fancy for Option<T> where T: Iterator {}

fn want_fancy<F>(f: F) where F: Fancy {}

fn example() {
    want_fancy(Some(5));
//  (BEFORE)   ^^^^^^^ `{integer}` is not an iterator
//  (AFTER)         ^  `{integer}` is not an iterator
}
```

I had used a (slightly more complex) example as an illustrative example in rust-lang#108254 , but hadn't actually turned it into a test, because I had (incorrectly) believed at the time it was covered by existing behavior. It turns out that `Some` is slightly "special" in that it resolves differently from the other `enum` constructors I had tried, and therefore this test was actually broken.

I've now updated the tests to include this example, and fixed the code to correctly resolve the `Some` constructor so that the span of the error is reduced.
  • Loading branch information
matthiaskrgr authored Mar 2, 2023
2 parents 58ad049 + be15f17 commit 82d7520
Show file tree
Hide file tree
Showing 4 changed files with 463 additions and 8 deletions.
20 changes: 17 additions & 3 deletions compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.parent(expr_ctor_def_id)
}
hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
// If this is a variant, its parent is the type definition.
if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
// For a typical enum like
// `enum Blah<T> { Variant(T) }`
// we get the following resolutions:
// - expr_ctor_def_id ::: DefId(0:29 ~ source_file[b442]::Blah::Variant::{constructor#0})
// - self.tcx.parent(expr_ctor_def_id) ::: DefId(0:28 ~ source_file[b442]::Blah::Variant)
// - self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) ::: DefId(0:26 ~ source_file[b442]::Blah)

// Therefore, we need to go up once to obtain the variant and up twice to obtain the type.
// Note that this pattern still holds even when we `use` a variant or `use` an enum type to rename it, or chain `use` expressions
// together; this resolution is handled automatically by `qpath_res`.

// FIXME: Deal with type aliases?
if in_ty_adt.did() == self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) {
// The constructor definition refers to the "constructor" of the variant:
// For example, `Some(5)` triggers this case.
self.tcx.parent(expr_ctor_def_id)
} else {
// FIXME: Deal with type aliases?
return Err(expr);
}
expr_ctor_def_id
}
_ => {
return Err(expr);
Expand Down
74 changes: 74 additions & 0 deletions tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,85 @@ struct Burrito<F> {
filling: F,
}

impl<It: Iterator> T1 for Option<It> {}

impl<'a, A: T1> T1 for &'a A {}

fn want<V: T1>(_x: V) {}

enum ExampleTuple<T> {
ExampleTupleVariant(T),
}
use ExampleDifferentTupleVariantName as ExampleYetAnotherTupleVariantName;
use ExampleTuple as ExampleOtherTuple;
use ExampleTuple::ExampleTupleVariant as ExampleDifferentTupleVariantName;
use ExampleTuple::*;

impl<A> T1 for ExampleTuple<A> where A: T3 {}

enum ExampleStruct<T> {
ExampleStructVariant { field: T },
}
use ExampleDifferentStructVariantName as ExampleYetAnotherStructVariantName;
use ExampleStruct as ExampleOtherStruct;
use ExampleStruct::ExampleStructVariant as ExampleDifferentStructVariantName;
use ExampleStruct::*;

impl<A> T1 for ExampleStruct<A> where A: T3 {}

struct ExampleActuallyTupleStruct<T>(T, i32);
use ExampleActuallyTupleStruct as ExampleActuallyTupleStructOther;

impl<A> T1 for ExampleActuallyTupleStruct<A> where A: T3 {}

fn example<Q>(q: Q) {
want(Wrapper { value: Burrito { filling: q } });
//~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]

want(Some(()));
//~^ ERROR `()` is not an iterator [E0277]

want(Some(q));
//~^ ERROR `Q` is not an iterator [E0277]

want(&Some(q));
//~^ ERROR `Q` is not an iterator [E0277]

want(&ExampleTuple::ExampleTupleVariant(q));
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleTupleVariant(q));
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleOtherTuple::ExampleTupleVariant(q));
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleDifferentTupleVariantName(q));
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleYetAnotherTupleVariantName(q));
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleStruct::ExampleStructVariant { field: q });
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleStructVariant { field: q });
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleOtherStruct::ExampleStructVariant { field: q });
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleDifferentStructVariantName { field: q });
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleYetAnotherStructVariantName { field: q });
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleActuallyTupleStruct(q, 0));
//~^ ERROR `Q: T3` is not satisfied [E0277]

want(&ExampleActuallyTupleStructOther(q, 0));
//~^ ERROR `Q: T3` is not satisfied [E0277]
}

fn main() {}
Loading

0 comments on commit 82d7520

Please sign in to comment.