Apply fallback to scalar type variables before final obligation resolution
This commit is contained in:
parent
b183612610
commit
d01630c8f3
@ -512,6 +512,8 @@ fn new(
|
||||
fn resolve_all(self) -> InferenceResult {
|
||||
let InferenceContext { mut table, mut result, .. } = self;
|
||||
|
||||
table.fallback_if_possible();
|
||||
|
||||
// FIXME resolve obligations as well (use Guidance if necessary)
|
||||
table.resolve_obligations_as_possible();
|
||||
|
||||
|
@ -350,6 +350,51 @@ pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
|
||||
self.resolve_with_fallback(t, &|_, _, d, _| d)
|
||||
}
|
||||
|
||||
/// Apply a fallback to unresolved scalar types. Integer type variables and float type
|
||||
/// variables are replaced with i32 and f64, respectively.
|
||||
///
|
||||
/// This method is only intended to be called just before returning inference results (i.e. in
|
||||
/// `InferenceContext::resolve_all()`).
|
||||
///
|
||||
/// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
|
||||
/// whereas rustc replaces them with `()` or `!`.
|
||||
pub(super) fn fallback_if_possible(&mut self) {
|
||||
let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
|
||||
let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
|
||||
|
||||
let scalar_vars: Vec<_> = self
|
||||
.type_variable_table
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, flags)| {
|
||||
let kind = if flags.contains(TypeVariableFlags::INTEGER) {
|
||||
TyVariableKind::Integer
|
||||
} else if flags.contains(TypeVariableFlags::FLOAT) {
|
||||
TyVariableKind::Float
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
|
||||
// without directly constructing them from `index`?
|
||||
let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
|
||||
Some(var)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for var in scalar_vars {
|
||||
let maybe_resolved = self.resolve_ty_shallow(&var);
|
||||
if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
|
||||
let fallback = match kind {
|
||||
TyVariableKind::Integer => &int_fallback,
|
||||
TyVariableKind::Float => &float_fallback,
|
||||
TyVariableKind::General => unreachable!(),
|
||||
};
|
||||
self.unify(&var, fallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
|
||||
pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
|
||||
let result = match self.try_unify(ty1, ty2) {
|
||||
|
@ -4100,3 +4100,68 @@ fn f<T>(t: T)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bin_op_with_scalar_fallback() {
|
||||
// Extra impls are significant so that chalk doesn't give us definite guidances.
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: add
|
||||
use core::ops::Add;
|
||||
|
||||
struct Vec2<T>(T, T);
|
||||
|
||||
impl Add for Vec2<i32> {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||
}
|
||||
impl Add for Vec2<u32> {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||
}
|
||||
impl Add for Vec2<f32> {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||
}
|
||||
impl Add for Vec2<f64> {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let a = Vec2(1, 2);
|
||||
let b = Vec2(3, 4);
|
||||
let c = a + b;
|
||||
//^ Vec2<i32>
|
||||
let a = Vec2(1., 2.);
|
||||
let b = Vec2(3., 4.);
|
||||
let c = a + b;
|
||||
//^ Vec2<f64>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trait_method_with_scalar_fallback() {
|
||||
check_types(
|
||||
r#"
|
||||
trait Trait {
|
||||
type Output;
|
||||
fn foo(&self) -> Self::Output;
|
||||
}
|
||||
impl<T> Trait for T {
|
||||
type Output = T;
|
||||
fn foo(&self) -> Self::Output { loop {} }
|
||||
}
|
||||
fn test() {
|
||||
let a = 42;
|
||||
let b = a.foo();
|
||||
//^ i32
|
||||
let a = 3.14;
|
||||
let b = a.foo();
|
||||
//^ f64
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user