mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	Merge #8938
8938: internal: Fix #8931 r=flodiebold a=flodiebold - and add some better checking for similar bugs Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
		
						commit
						0ec4ce1e9b
					
				@ -2053,7 +2053,7 @@ impl Type {
 | 
				
			|||||||
        name: Option<&Name>,
 | 
					        name: Option<&Name>,
 | 
				
			||||||
        mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
 | 
					        mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
 | 
				
			||||||
    ) -> Option<T> {
 | 
					    ) -> Option<T> {
 | 
				
			||||||
        let canonical = hir_ty::replace_errors_with_variables(self.ty.clone());
 | 
					        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let env = self.env.clone();
 | 
					        let env = self.env.clone();
 | 
				
			||||||
        let krate = krate.id;
 | 
					        let krate = krate.id;
 | 
				
			||||||
@ -2222,7 +2222,7 @@ impl Type {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
 | 
					    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
 | 
				
			||||||
        let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone()));
 | 
					        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
 | 
				
			||||||
        could_unify(db, self.env.clone(), &tys)
 | 
					        could_unify(db, self.env.clone(), &tys)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -505,9 +505,10 @@ impl<'db> SemanticsImpl<'db> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
 | 
					    fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
 | 
				
			||||||
        // FIXME: this erases Substs
 | 
					        // FIXME: this erases Substs, we should instead record the correct
 | 
				
			||||||
 | 
					        // substitution during inference and use that
 | 
				
			||||||
        let func = self.resolve_method_call(call)?;
 | 
					        let func = self.resolve_method_call(call)?;
 | 
				
			||||||
        let (ty, _) = self.db.value_ty(func.into()).into_value_and_skipped_binders();
 | 
					        let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
 | 
				
			||||||
        let resolver = self.analyze(call.syntax()).resolver;
 | 
					        let resolver = self.analyze(call.syntax()).resolver;
 | 
				
			||||||
        let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
 | 
					        let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
 | 
				
			||||||
        let mut res = ty.as_callable(self.db)?;
 | 
					        let mut res = ty.as_callable(self.db)?;
 | 
				
			||||||
 | 
				
			|||||||
@ -43,7 +43,6 @@ use hir_def::{
 | 
				
			|||||||
    type_ref::{ConstScalar, Rawness},
 | 
					    type_ref::{ConstScalar, Rawness},
 | 
				
			||||||
    TypeParamId,
 | 
					    TypeParamId,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use stdx::always;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{db::HirDatabase, utils::generics};
 | 
					use crate::{db::HirDatabase, utils::generics};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -329,14 +328,17 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
 | 
				
			|||||||
    t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
 | 
					    t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result>
 | 
					/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
 | 
				
			||||||
 | 
					/// ensures there are no unbound variables or inference variables anywhere in
 | 
				
			||||||
 | 
					/// the `t`.
 | 
				
			||||||
 | 
					pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T::Result>
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
    T: HasInterner<Interner = Interner> + Fold<Interner>,
 | 
					    T: HasInterner<Interner = Interner> + Fold<Interner> + Clone,
 | 
				
			||||||
    T::Result: HasInterner<Interner = Interner>,
 | 
					    T::Result: HasInterner<Interner = Interner>,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use chalk_ir::{
 | 
					    use chalk_ir::{
 | 
				
			||||||
        fold::{Folder, SuperFold},
 | 
					        fold::{Folder, SuperFold},
 | 
				
			||||||
        Fallible,
 | 
					        Fallible, NoSolution,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    struct ErrorReplacer {
 | 
					    struct ErrorReplacer {
 | 
				
			||||||
        vars: usize,
 | 
					        vars: usize,
 | 
				
			||||||
@ -363,18 +365,88 @@ where
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        fn fold_inference_ty(
 | 
					        fn fold_inference_ty(
 | 
				
			||||||
            &mut self,
 | 
					            &mut self,
 | 
				
			||||||
            var: InferenceVar,
 | 
					            _var: InferenceVar,
 | 
				
			||||||
            kind: TyVariableKind,
 | 
					            _kind: TyVariableKind,
 | 
				
			||||||
            _outer_binder: DebruijnIndex,
 | 
					            _outer_binder: DebruijnIndex,
 | 
				
			||||||
        ) -> Fallible<Ty> {
 | 
					        ) -> Fallible<Ty> {
 | 
				
			||||||
            always!(false);
 | 
					            if cfg!(debug_assertions) {
 | 
				
			||||||
            Ok(TyKind::InferenceVar(var, kind).intern(&Interner))
 | 
					                // we don't want to just panic here, because then the error message
 | 
				
			||||||
 | 
					                // won't contain the whole thing, which would not be very helpful
 | 
				
			||||||
 | 
					                Err(NoSolution)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Ok(TyKind::Error.intern(&Interner))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn fold_free_var_ty(
 | 
				
			||||||
 | 
					            &mut self,
 | 
				
			||||||
 | 
					            _bound_var: BoundVar,
 | 
				
			||||||
 | 
					            _outer_binder: DebruijnIndex,
 | 
				
			||||||
 | 
					        ) -> Fallible<Ty> {
 | 
				
			||||||
 | 
					            if cfg!(debug_assertions) {
 | 
				
			||||||
 | 
					                // we don't want to just panic here, because then the error message
 | 
				
			||||||
 | 
					                // won't contain the whole thing, which would not be very helpful
 | 
				
			||||||
 | 
					                Err(NoSolution)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Ok(TyKind::Error.intern(&Interner))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn fold_inference_const(
 | 
				
			||||||
 | 
					            &mut self,
 | 
				
			||||||
 | 
					            _ty: Ty,
 | 
				
			||||||
 | 
					            _var: InferenceVar,
 | 
				
			||||||
 | 
					            _outer_binder: DebruijnIndex,
 | 
				
			||||||
 | 
					        ) -> Fallible<Const> {
 | 
				
			||||||
 | 
					            if cfg!(debug_assertions) {
 | 
				
			||||||
 | 
					                Err(NoSolution)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Ok(dummy_usize_const())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn fold_free_var_const(
 | 
				
			||||||
 | 
					            &mut self,
 | 
				
			||||||
 | 
					            _ty: Ty,
 | 
				
			||||||
 | 
					            _bound_var: BoundVar,
 | 
				
			||||||
 | 
					            _outer_binder: DebruijnIndex,
 | 
				
			||||||
 | 
					        ) -> Fallible<Const> {
 | 
				
			||||||
 | 
					            if cfg!(debug_assertions) {
 | 
				
			||||||
 | 
					                Err(NoSolution)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Ok(dummy_usize_const())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn fold_inference_lifetime(
 | 
				
			||||||
 | 
					            &mut self,
 | 
				
			||||||
 | 
					            _var: InferenceVar,
 | 
				
			||||||
 | 
					            _outer_binder: DebruijnIndex,
 | 
				
			||||||
 | 
					        ) -> Fallible<Lifetime> {
 | 
				
			||||||
 | 
					            if cfg!(debug_assertions) {
 | 
				
			||||||
 | 
					                Err(NoSolution)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Ok(static_lifetime())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn fold_free_var_lifetime(
 | 
				
			||||||
 | 
					            &mut self,
 | 
				
			||||||
 | 
					            _bound_var: BoundVar,
 | 
				
			||||||
 | 
					            _outer_binder: DebruijnIndex,
 | 
				
			||||||
 | 
					        ) -> Fallible<Lifetime> {
 | 
				
			||||||
 | 
					            if cfg!(debug_assertions) {
 | 
				
			||||||
 | 
					                Err(NoSolution)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Ok(static_lifetime())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let mut error_replacer = ErrorReplacer { vars: 0 };
 | 
					    let mut error_replacer = ErrorReplacer { vars: 0 };
 | 
				
			||||||
    let value = t
 | 
					    let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
 | 
				
			||||||
        .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST)
 | 
					        Ok(t) => t,
 | 
				
			||||||
        .expect("fold failed unexpectedly");
 | 
					        Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    let kinds = (0..error_replacer.vars).map(|_| {
 | 
					    let kinds = (0..error_replacer.vars).map(|_| {
 | 
				
			||||||
        chalk_ir::CanonicalVarKind::new(
 | 
					        chalk_ir::CanonicalVarKind::new(
 | 
				
			||||||
            chalk_ir::VariableKind::Ty(TyVariableKind::General),
 | 
					            chalk_ir::VariableKind::Ty(TyVariableKind::General),
 | 
				
			||||||
 | 
				
			|||||||
@ -454,4 +454,34 @@ mod foo {
 | 
				
			|||||||
            "#]],
 | 
					            "#]],
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn issue_8931() {
 | 
				
			||||||
 | 
					        check(
 | 
				
			||||||
 | 
					            r#"
 | 
				
			||||||
 | 
					#[lang = "fn_once"]
 | 
				
			||||||
 | 
					trait FnOnce<Args> {
 | 
				
			||||||
 | 
					    type Output;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					struct S;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Foo;
 | 
				
			||||||
 | 
					impl Foo {
 | 
				
			||||||
 | 
					    fn foo(&self) -> &[u8] { loop {} }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl S {
 | 
				
			||||||
 | 
					    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn f(&mut self, v: Foo) {
 | 
				
			||||||
 | 
					        self.indented(|this| v.$0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					        "#,
 | 
				
			||||||
 | 
					            expect![[r#"
 | 
				
			||||||
 | 
					                me foo() fn(&self) -> &[u8]
 | 
				
			||||||
 | 
					            "#]],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user