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

Emit alias-eq when equating numeric var and projection #108828

Merged
merged 3 commits into from
Mar 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 4 additions & 3 deletions compiler/rustc_hir_typeck/src/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs_ty,
op,
);
self.demand_suptype(expr.span, builtin_return_ty, return_ty);
self.demand_eqtype(expr.span, builtin_return_ty, return_ty);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This demand_suptype doesn't matter because the only types we're gonna encounter here are scalars.

builtin_return_ty
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But returning builtin_return_ty here means that when we equate _#0i and _#1i, the type we return will be _#0i instead of <#_0i as Add<_#i1>>::Output, which helps guide inference in the solver.

} else {
return_ty
}

return_ty
}
}
}
Expand Down
31 changes: 22 additions & 9 deletions compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,15 +411,28 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}

ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
t,
),

ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
t,
),
ty::Infer(ty::IntVar(vid)) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also needed to fix the canonicalizer bug for int and float vars as well...

let nt = self.infcx.opportunistic_resolve_int_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
t,
)
}
}
ty::Infer(ty::FloatVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_float_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
t,
)
}
}

ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
Expand Down
26 changes: 18 additions & 8 deletions compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,20 +119,30 @@ impl<'tcx> InferCtxt<'tcx> {
self.unify_float_variable(!a_is_expected, v_id, v)
}

// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
// We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
(
ty::Alias(AliasKind::Projection, _),
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
)
| (
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
ty::Alias(AliasKind::Projection, _),
) if self.tcx.trait_solver_next() => {
bug!()
}

(ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => {
(_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
if self.tcx.trait_solver_next() =>
{
relation.register_type_equate_obligation(a, b);
Ok(b)
}
(_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => {
relation.register_type_equate_obligation(b, a);
Ok(a)
}

// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
}

_ => ty::relate::super_relate_tys(relation, a, b),
}
}
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,28 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().const_unification_table().find(var)
}

/// Resolves an int var to a rigid int type, if it was constrained to one,
/// or else the root int var in the unification table.
pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
let mut inner = self.inner.borrow_mut();
if let Some(value) = inner.int_unification_table().probe_value(vid) {
value.to_type(self.tcx)
} else {
self.tcx.mk_int_var(inner.int_unification_table().find(vid))
}
}

/// Resolves a float var to a rigid int type, if it was constrained to one,
/// or else the root float var in the unification table.
pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
let mut inner = self.inner.borrow_mut();
if let Some(value) = inner.float_unification_table().probe_value(vid) {
value.to_type(self.tcx)
} else {
self.tcx.mk_float_var(inner.float_unification_table().find(vid))
}
}

/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@ impl<'tcx> Term<'tcx> {

pub fn is_infer(&self) -> bool {
match self.unpack() {
TermKind::Ty(ty) => ty.is_ty_or_numeric_infer(),
TermKind::Ty(ty) => ty.is_ty_var(),
TermKind::Const(ct) => ct.is_ct_infer(),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,16 +278,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
}
}
ty::Infer(ty::IntVar(_)) => {
let nt = self.infcx.shallow_resolve(t);
ty::Infer(ty::IntVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_int_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
}
}
ty::Infer(ty::FloatVar(_)) => {
let nt = self.infcx.shallow_resolve(t);
ty::Infer(ty::FloatVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_float_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/issues/issue-66667-function-cmp-cycle.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
fn first() {
second == 1 //~ ERROR binary operation
//~^ ERROR mismatched types
//~| ERROR mismatched types
}

fn second() {
first == 1 //~ ERROR binary operation
//~^ ERROR mismatched types
//~| ERROR mismatched types
}

fn bar() {
bar == 1 //~ ERROR binary operation
//~^ ERROR mismatched types
//~| ERROR mismatched types
}

fn main() {}
34 changes: 29 additions & 5 deletions tests/ui/issues/issue-66667-function-cmp-cycle.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,65 @@ LL | second == 1
= note: expected fn item `fn() {second}`
found type `{integer}`

error[E0308]: mismatched types
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the changes to typeck, we end up emitting this additional error. I can work around it pretty easily by checking if the output type of the binop references errors before returning builtin_return_ty a few files up, but I also think that it's fine? Like, this is a meaningful error 😅

--> $DIR/issue-66667-function-cmp-cycle.rs:2:5
|
LL | fn first() {
| - help: try adding a return type: `-> bool`
LL | second == 1
| ^^^^^^^^^^^ expected `()`, found `bool`

error[E0369]: binary operation `==` cannot be applied to type `fn() {first}`
--> $DIR/issue-66667-function-cmp-cycle.rs:7:11
--> $DIR/issue-66667-function-cmp-cycle.rs:8:11
|
LL | first == 1
| ----- ^^ - {integer}
| |
| fn() {first}

error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:7:14
--> $DIR/issue-66667-function-cmp-cycle.rs:8:14
|
LL | first == 1
| ^ expected fn item, found integer
|
= note: expected fn item `fn() {first}`
found type `{integer}`

error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:8:5
|
LL | fn second() {
| - help: try adding a return type: `-> bool`
LL | first == 1
| ^^^^^^^^^^ expected `()`, found `bool`

error[E0369]: binary operation `==` cannot be applied to type `fn() {bar}`
--> $DIR/issue-66667-function-cmp-cycle.rs:12:9
--> $DIR/issue-66667-function-cmp-cycle.rs:14:9
|
LL | bar == 1
| --- ^^ - {integer}
| |
| fn() {bar}

error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:12:12
--> $DIR/issue-66667-function-cmp-cycle.rs:14:12
|
LL | bar == 1
| ^ expected fn item, found integer
|
= note: expected fn item `fn() {bar}`
found type `{integer}`

error: aborting due to 6 previous errors
error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:14:5
|
LL | fn bar() {
| - help: try adding a return type: `-> bool`
LL | bar == 1
| ^^^^^^^^ expected `()`, found `bool`

error: aborting due to 9 previous errors

Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.
21 changes: 21 additions & 0 deletions tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// check-pass

trait Mirror {
type Assoc;
}

impl<T> Mirror for T {
type Assoc = T;
}

trait Test {}
impl Test for i64 {}
impl Test for u64 {}

fn mirror_me<T: Mirror>(t: T, s: <T as Mirror>::Assoc) where <T as Mirror>::Assoc: Test {}

fn main() {
let mut x = 0;
mirror_me(x, 1);
x = 1i64;
}
18 changes: 18 additions & 0 deletions tests/ui/traits/new-solver/int-var-alias-eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// check-pass
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
// compile-flags: -Ztrait-solver=next

// HIR typeck ends up equating `<_#0i as Add>::Output == _#0i`.
// Want to make sure that we emit an alias-eq goal for this,
// instead of treating it as a type error and bailing.

fn test() {
// fallback
let x = 1 + 2;
}

fn test2() -> u32 {
// expectation from return ty
1 + 2
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// compile-flags: -Ztrait-solver=next
// known-bug: unknown
// check-pass

fn main() {
(0u8 + 0u8) as char;
Expand Down

This file was deleted.