Merge commit '21b06c1beb' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2023-12-18 09:21:55 +02:00
parent cac74d98f6
commit e37cf75791
59 changed files with 1080 additions and 477 deletions

View file

@ -113,7 +113,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
// FIXME(const-generic-body): We should not get the return type in this way.
ctx.return_ty = c
.lookup(db.upcast())
.thing
.expected_ty
.box_any()
.downcast::<InTypeConstIdMetadata>()
.unwrap()

View file

@ -262,7 +262,7 @@ impl InferenceContext<'_> {
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
let mut expected = self.resolve_ty_shallow(expected);
if is_non_ref_pat(self.body, pat) {
if self.is_non_ref_pat(self.body, pat) {
let mut pat_adjustments = Vec::new();
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
pat_adjustments.push(expected.clone());
@ -496,24 +496,28 @@ impl InferenceContext<'_> {
self.infer_expr(expr, &Expectation::has_type(expected.clone()))
}
}
fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
match &body[pat] {
Pat::Tuple { .. }
| Pat::TupleStruct { .. }
| Pat::Record { .. }
| Pat::Range { .. }
| Pat::Slice { .. } => true,
Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
Pat::Path(..) => true,
Pat::ConstBlock(..) => true,
Pat::Lit(expr) => !matches!(
body[*expr],
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
),
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
fn is_non_ref_pat(&mut self, body: &hir_def::body::Body, pat: PatId) -> bool {
match &body[pat] {
Pat::Tuple { .. }
| Pat::TupleStruct { .. }
| Pat::Record { .. }
| Pat::Range { .. }
| Pat::Slice { .. } => true,
Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
Pat::Path(p) => {
let v = self.resolve_value_path_inner(p, pat.into());
v.is_some_and(|x| !matches!(x.0, hir_def::resolver::ValueNs::ConstId(_)))
}
Pat::ConstBlock(..) => false,
Pat::Lit(expr) => !matches!(
body[*expr],
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
),
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
false
}
}
}
}

View file

@ -40,33 +40,7 @@ impl InferenceContext<'_> {
}
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
let last = path.segments().last()?;
// Don't use `self.make_ty()` here as we need `orig_ns`.
let ctx =
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
// FIXME: report error, unresolved first path segment
let value_or_partial =
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
match value_or_partial {
ResolveValueResult::ValueNs(it, _) => (it, None),
ResolveValueResult::Partial(def, remaining_index, _) => self
.resolve_assoc_item(def, path, remaining_index, id)
.map(|(it, substs)| (it, Some(substs)))?,
}
};
let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
let value_def = match value {
ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) {
@ -144,6 +118,41 @@ impl InferenceContext<'_> {
Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
}
pub(super) fn resolve_value_path_inner(
&mut self,
path: &Path,
id: ExprOrPatId,
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
let last = path.segments().last()?;
// Don't use `self.make_ty()` here as we need `orig_ns`.
let ctx =
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
// FIXME: report error, unresolved first path segment
let value_or_partial =
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
match value_or_partial {
ResolveValueResult::ValueNs(it, _) => (it, None),
ResolveValueResult::Partial(def, remaining_index, _) => self
.resolve_assoc_item(def, path, remaining_index, id)
.map(|(it, substs)| (it, Some(substs)))?,
}
};
Some((value, self_subst))
}
fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
let predicates = self.db.generic_predicates(def);
for predicate in predicates.iter() {

View file

@ -113,7 +113,9 @@ pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
resolver: &'a Resolver,
in_binders: DebruijnIndex,
owner: TypeOwnerId,
// FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
// where expected
owner: Option<TypeOwnerId>,
/// Note: Conceptually, it's thinkable that we could be in a location where
/// some type params should be represented as placeholders, and others
/// should be converted to variables. I think in practice, this isn't
@ -127,6 +129,14 @@ pub struct TyLoweringContext<'a> {
impl<'a> TyLoweringContext<'a> {
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self {
Self::new_maybe_unowned(db, resolver, Some(owner))
}
pub fn new_maybe_unowned(
db: &'a dyn HirDatabase,
resolver: &'a Resolver,
owner: Option<TypeOwnerId>,
) -> Self {
let impl_trait_mode = ImplTraitLoweringState::Disallowed;
let type_param_mode = ParamLoweringMode::Placeholder;
let in_binders = DebruijnIndex::INNERMOST;
@ -213,10 +223,11 @@ impl<'a> TyLoweringContext<'a> {
}
pub fn lower_const(&self, const_ref: &ConstRef, const_type: Ty) -> Const {
let Some(owner) = self.owner else { return unknown_const(const_type) };
const_or_path_to_chalk(
self.db,
self.resolver,
self.owner,
owner,
const_type,
const_ref,
self.type_param_mode,
@ -1768,10 +1779,11 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
let resolver = t.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, t.into())
.with_type_param_mode(ParamLoweringMode::Variable);
if db.type_alias_data(t).is_extern {
let type_alias_data = db.type_alias_data(t);
if type_alias_data.is_extern {
Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
} else {
let type_ref = &db.type_alias_data(t).type_ref;
let type_ref = &type_alias_data.type_ref;
let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
make_binders(db, &generics, inner)
}
@ -2042,7 +2054,7 @@ pub(crate) fn const_or_path_to_chalk(
.intern_in_type_const(InTypeConstLoc {
id: it,
owner,
thing: Box::new(InTypeConstIdMetadata(expected_ty.clone())),
expected_ty: Box::new(InTypeConstIdMetadata(expected_ty.clone())),
})
.into();
intern_const_scalar(

View file

@ -9,11 +9,10 @@ use super::visit_module;
fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
let (mut db, pos) = TestDB::with_position(
"
//- /lib.rs
fn foo() -> i32 {
$01 + 1
}
",
//- /lib.rs
fn foo() -> i32 {
$01 + 1
}",
);
{
let events = db.log_executed(|| {
@ -27,12 +26,11 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
}
let new_text = "
fn foo() -> i32 {
1
+
1
}
";
fn foo() -> i32 {
1
+
1
}";
db.set_file_text(pos.file_id, Arc::from(new_text));
@ -47,3 +45,55 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
assert!(!format!("{events:?}").contains("infer"), "{events:#?}")
}
}
#[test]
fn typing_inside_a_function_should_not_invalidate_types_in_another() {
let (mut db, pos) = TestDB::with_position(
"
//- /lib.rs
fn foo() -> f32 {
1.0 + 2.0
}
fn bar() -> i32 {
$01 + 1
}
fn baz() -> i32 {
1 + 1
}",
);
{
let events = db.log_executed(|| {
let module = db.module_for_file(pos.file_id);
let crate_def_map = module.def_map(&db);
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
db.infer(def);
});
});
assert!(format!("{events:?}").contains("infer"))
}
let new_text = "
fn foo() -> f32 {
1.0 + 2.0
}
fn bar() -> i32 {
53
}
fn baz() -> i32 {
1 + 1
}
";
db.set_file_text(pos.file_id, Arc::from(new_text));
{
let events = db.log_executed(|| {
let module = db.module_for_file(pos.file_id);
let crate_def_map = module.def_map(&db);
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
db.infer(def);
});
});
assert!(format!("{events:?}").matches("infer").count() == 1, "{events:#?}")
}
}

View file

@ -1153,3 +1153,41 @@ fn main() {
"#,
);
}
#[test]
fn type_mismatch_pat_const_reference() {
check_no_mismatches(
r#"
const TEST_STR: &'static str = "abcd";
fn main() {
let s = "abcd";
match s {
TEST_STR => (),
_ => (),
}
}
"#,
);
check(
r#"
struct Foo<T>(T);
impl<T> Foo<T> {
const TEST_I32_REF: &'static i32 = &3;
const TEST_I32: i32 = 3;
}
fn main() {
match &6 {
Foo::<i32>::TEST_I32_REF => (),
Foo::<i32>::TEST_I32 => (),
//^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
_ => (),
}
}
"#,
);
}