mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 21:35:20 +00:00
internal: Record mismatches of pattern types.
This commit is contained in:
parent
49a5d6a8d4
commit
472317c008
6 changed files with 93 additions and 11 deletions
|
@ -211,7 +211,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||||
|
|
||||||
// FIXME: Due to shortcomings in the current type system implementation, only emit this
|
// FIXME: Due to shortcomings in the current type system implementation, only emit this
|
||||||
// diagnostic if there are no type mismatches in the containing function.
|
// diagnostic if there are no type mismatches in the containing function.
|
||||||
if self.infer.type_mismatches.iter().next().is_some() {
|
if self.infer.expr_type_mismatches().next().is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,8 +137,12 @@ pub struct InferenceResult {
|
||||||
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
|
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
|
||||||
diagnostics: Vec<InferenceDiagnostic>,
|
diagnostics: Vec<InferenceDiagnostic>,
|
||||||
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
||||||
|
/// For each pattern record the type it resolves to.
|
||||||
|
///
|
||||||
|
/// **Note**: When a pattern type is resolved it may still contain
|
||||||
|
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
||||||
pub type_of_pat: ArenaMap<PatId, Ty>,
|
pub type_of_pat: ArenaMap<PatId, Ty>,
|
||||||
pub(super) type_mismatches: ArenaMap<ExprId, TypeMismatch>,
|
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||||
/// Interned Unknown to return references to.
|
/// Interned Unknown to return references to.
|
||||||
standard_types: InternedStandardTypes,
|
standard_types: InternedStandardTypes,
|
||||||
}
|
}
|
||||||
|
@ -163,7 +167,22 @@ impl InferenceResult {
|
||||||
self.assoc_resolutions.get(&id.into()).copied()
|
self.assoc_resolutions.get(&id.into()).copied()
|
||||||
}
|
}
|
||||||
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
||||||
self.type_mismatches.get(expr)
|
self.type_mismatches.get(&expr.into())
|
||||||
|
}
|
||||||
|
pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
|
||||||
|
self.type_mismatches.get(&pat.into())
|
||||||
|
}
|
||||||
|
pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
|
||||||
|
self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
|
||||||
|
ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
|
||||||
|
self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
|
||||||
|
ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn add_diagnostics(
|
pub fn add_diagnostics(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
let could_unify = self.unify(&ty, &expected.ty);
|
let could_unify = self.unify(&ty, &expected.ty);
|
||||||
if !could_unify {
|
if !could_unify {
|
||||||
self.result.type_mismatches.insert(
|
self.result.type_mismatches.insert(
|
||||||
tgt_expr,
|
tgt_expr.into(),
|
||||||
TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
|
TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,10 @@ impl<'a> InferenceContext<'a> {
|
||||||
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
||||||
let ty = self.infer_expr_inner(expr, &expected);
|
let ty = self.infer_expr_inner(expr, &expected);
|
||||||
let ty = if !self.coerce(&ty, &expected.coercion_target()) {
|
let ty = if !self.coerce(&ty, &expected.coercion_target()) {
|
||||||
self.result
|
self.result.type_mismatches.insert(
|
||||||
.type_mismatches
|
expr.into(),
|
||||||
.insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() });
|
TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
|
||||||
|
);
|
||||||
// Return actual type when type mismatch.
|
// Return actual type when type mismatch.
|
||||||
// This is needed for diagnostic when return type mismatch.
|
// This is needed for diagnostic when return type mismatch.
|
||||||
ty
|
ty
|
||||||
|
|
|
@ -10,7 +10,7 @@ use hir_def::{
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
|
|
||||||
use super::{BindingMode, Expectation, InferenceContext};
|
use super::{BindingMode, Expectation, InferenceContext, TypeMismatch};
|
||||||
use crate::{
|
use crate::{
|
||||||
lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder,
|
lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder,
|
||||||
TyExt, TyKind,
|
TyExt, TyKind,
|
||||||
|
@ -266,7 +266,10 @@ impl<'a> InferenceContext<'a> {
|
||||||
// use a new type variable if we got error type here
|
// use a new type variable if we got error type here
|
||||||
let ty = self.insert_type_vars_shallow(ty);
|
let ty = self.insert_type_vars_shallow(ty);
|
||||||
if !self.unify(&ty, expected) {
|
if !self.unify(&ty, expected) {
|
||||||
// FIXME record mismatch, we need to change the type of self.type_mismatches for that
|
self.result.type_mismatches.insert(
|
||||||
|
pat.into(),
|
||||||
|
TypeMismatch { expected: expected.clone(), actual: ty.clone() },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let ty = self.resolve_ty_as_possible(ty);
|
let ty = self.resolve_ty_as_possible(ty);
|
||||||
self.write_pat_ty(pat, ty.clone());
|
self.write_pat_ty(pat, ty.clone());
|
||||||
|
|
|
@ -130,7 +130,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||||
}
|
}
|
||||||
Err(SyntheticSyntax) => continue,
|
Err(SyntheticSyntax) => continue,
|
||||||
};
|
};
|
||||||
types.push((syntax_ptr, ty));
|
types.push((syntax_ptr.clone(), ty));
|
||||||
|
if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) {
|
||||||
|
mismatches.push((syntax_ptr, mismatch));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (expr, ty) in inference_result.type_of_expr.iter() {
|
for (expr, ty) in inference_result.type_of_expr.iter() {
|
||||||
|
|
|
@ -546,7 +546,9 @@ fn infer_const_pattern() {
|
||||||
273..276 'Bar': usize
|
273..276 'Bar': usize
|
||||||
280..283 'Bar': usize
|
280..283 'Bar': usize
|
||||||
200..223: expected (), got Foo
|
200..223: expected (), got Foo
|
||||||
|
211..214: expected (), got Foo
|
||||||
262..285: expected (), got usize
|
262..285: expected (), got usize
|
||||||
|
273..276: expected (), got usize
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -703,7 +705,7 @@ fn box_pattern() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tuple_ellipsis_pattern() {
|
fn tuple_ellipsis_pattern() {
|
||||||
check_infer(
|
check_infer_with_mismatches(
|
||||||
r#"
|
r#"
|
||||||
fn foo(tuple: (u8, i16, f32)) {
|
fn foo(tuple: (u8, i16, f32)) {
|
||||||
match tuple {
|
match tuple {
|
||||||
|
@ -744,6 +746,8 @@ fn foo(tuple: (u8, i16, f32)) {
|
||||||
186..200 '{/*too long*/}': ()
|
186..200 '{/*too long*/}': ()
|
||||||
209..210 '_': (u8, i16, f32)
|
209..210 '_': (u8, i16, f32)
|
||||||
214..216 '{}': ()
|
214..216 '{}': ()
|
||||||
|
136..142: expected (u8, i16, f32), got (u8, i16)
|
||||||
|
170..182: expected (u8, i16, f32), got (u8, i16, f32, _)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -851,3 +855,55 @@ fn f(e: Enum) {
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn type_mismatch_in_or_pattern() {
|
||||||
|
check_infer_with_mismatches(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
match (false,) {
|
||||||
|
(true | (),) => {}
|
||||||
|
(() | true,) => {}
|
||||||
|
(_ | (),) => {}
|
||||||
|
(() | _,) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
10..142 '{ ... } }': ()
|
||||||
|
16..140 'match ... }': ()
|
||||||
|
22..30 '(false,)': (bool,)
|
||||||
|
23..28 'false': bool
|
||||||
|
41..53 '(true | (),)': (bool,)
|
||||||
|
42..46 'true': bool
|
||||||
|
42..46 'true': bool
|
||||||
|
42..51 'true | ()': bool
|
||||||
|
49..51 '()': ()
|
||||||
|
57..59 '{}': ()
|
||||||
|
68..80 '(() | true,)': ((),)
|
||||||
|
69..71 '()': ()
|
||||||
|
69..78 '() | true': ()
|
||||||
|
74..78 'true': bool
|
||||||
|
74..78 'true': bool
|
||||||
|
84..86 '{}': ()
|
||||||
|
95..104 '(_ | (),)': (bool,)
|
||||||
|
96..97 '_': bool
|
||||||
|
96..102 '_ | ()': bool
|
||||||
|
100..102 '()': ()
|
||||||
|
108..110 '{}': ()
|
||||||
|
119..128 '(() | _,)': ((),)
|
||||||
|
120..122 '()': ()
|
||||||
|
120..126 '() | _': ()
|
||||||
|
125..126 '_': bool
|
||||||
|
132..134 '{}': ()
|
||||||
|
49..51: expected bool, got ()
|
||||||
|
68..80: expected (bool,), got ((),)
|
||||||
|
69..71: expected bool, got ()
|
||||||
|
69..78: expected bool, got ()
|
||||||
|
100..102: expected bool, got ()
|
||||||
|
119..128: expected (bool,), got ((),)
|
||||||
|
120..122: expected bool, got ()
|
||||||
|
120..126: expected bool, got ()
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue