mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
fix: Always explicitly set trait ref self types when lowering
This commit is contained in:
parent
70ee4e5545
commit
20f7ab5ab4
9 changed files with 80 additions and 64 deletions
|
@ -1556,7 +1556,7 @@ fn builtin_derive_macro() {
|
||||||
Bar,
|
Bar,
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct X(i32, Z, i64)
|
struct X(i32, Z, i64);
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Y {
|
struct Y {
|
||||||
field1: i32,
|
field1: i32,
|
||||||
|
@ -1574,20 +1574,20 @@ fn builtin_derive_macro() {
|
||||||
);
|
);
|
||||||
check_number(
|
check_number(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: default, derive, builtin_impls
|
//- minicore: default, derive, builtin_impls
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct X(i32, Y, i64)
|
struct X(i32, Y, i64);
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Y {
|
struct Y {
|
||||||
field1: i32,
|
field1: i32,
|
||||||
field2: u8,
|
field2: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
const GOAL: u8 = {
|
const GOAL: u8 = {
|
||||||
let x = X::default();
|
let x = X::default();
|
||||||
x.1.field2
|
x.1.field2
|
||||||
};
|
};
|
||||||
"#,
|
"#,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2828,7 +2828,7 @@ fn type_error() {
|
||||||
y.0
|
y.0
|
||||||
};
|
};
|
||||||
"#,
|
"#,
|
||||||
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))),
|
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::HasErrors)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -851,7 +851,7 @@ impl InferenceContext<'_> {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
|
for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
|
||||||
self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
|
*ty = self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
|
TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
|
||||||
|
|
|
@ -247,8 +247,12 @@ impl InferenceContext<'_> {
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
self.owner.into(),
|
self.owner.into(),
|
||||||
);
|
);
|
||||||
let trait_ref =
|
let trait_ref = ctx.lower_trait_ref_from_resolved_path(
|
||||||
ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
|
trait_,
|
||||||
|
resolved_segment,
|
||||||
|
self.table.new_type_var(),
|
||||||
|
);
|
||||||
|
|
||||||
self.resolve_trait_assoc_item(trait_ref, segment, id)
|
self.resolve_trait_assoc_item(trait_ref, segment, id)
|
||||||
}
|
}
|
||||||
(def, _) => {
|
(def, _) => {
|
||||||
|
|
|
@ -516,8 +516,11 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
TypeNs::TraitId(trait_) => {
|
TypeNs::TraitId(trait_) => {
|
||||||
let ty = match remaining_segments.len() {
|
let ty = match remaining_segments.len() {
|
||||||
1 => {
|
1 => {
|
||||||
let trait_ref =
|
let trait_ref = self.lower_trait_ref_from_resolved_path(
|
||||||
self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
|
trait_,
|
||||||
|
resolved_segment,
|
||||||
|
TyKind::Error.intern(Interner),
|
||||||
|
);
|
||||||
let segment = remaining_segments.first().unwrap();
|
let segment = remaining_segments.first().unwrap();
|
||||||
let found = self
|
let found = self
|
||||||
.db
|
.db
|
||||||
|
@ -952,11 +955,17 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
Substitution::from_iter(Interner, substs)
|
Substitution::from_iter(Interner, substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_trait_ref_from_path(
|
pub(crate) fn lower_trait_ref_from_resolved_path(
|
||||||
&self,
|
&self,
|
||||||
path: &Path,
|
resolved: TraitId,
|
||||||
explicit_self_ty: Option<Ty>,
|
segment: PathSegment<'_>,
|
||||||
) -> Option<TraitRef> {
|
explicit_self_ty: Ty,
|
||||||
|
) -> TraitRef {
|
||||||
|
let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
|
||||||
|
TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_trait_ref_from_path(&self, path: &Path, explicit_self_ty: Ty) -> Option<TraitRef> {
|
||||||
let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? {
|
let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? {
|
||||||
// FIXME(trait_alias): We need to handle trait alias here.
|
// FIXME(trait_alias): We need to handle trait alias here.
|
||||||
TypeNs::TraitId(tr) => tr,
|
TypeNs::TraitId(tr) => tr,
|
||||||
|
@ -966,21 +975,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
|
Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_trait_ref_from_resolved_path(
|
fn lower_trait_ref(&self, trait_ref: &HirTraitRef, explicit_self_ty: Ty) -> Option<TraitRef> {
|
||||||
&self,
|
|
||||||
resolved: TraitId,
|
|
||||||
segment: PathSegment<'_>,
|
|
||||||
explicit_self_ty: Option<Ty>,
|
|
||||||
) -> TraitRef {
|
|
||||||
let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
|
|
||||||
TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_trait_ref(
|
|
||||||
&self,
|
|
||||||
trait_ref: &HirTraitRef,
|
|
||||||
explicit_self_ty: Option<Ty>,
|
|
||||||
) -> Option<TraitRef> {
|
|
||||||
self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
|
self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,9 +983,9 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
&self,
|
&self,
|
||||||
segment: PathSegment<'_>,
|
segment: PathSegment<'_>,
|
||||||
resolved: TraitId,
|
resolved: TraitId,
|
||||||
explicit_self_ty: Option<Ty>,
|
explicit_self_ty: Ty,
|
||||||
) -> Substitution {
|
) -> Substitution {
|
||||||
self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty)
|
self.substs_from_path_segment(segment, Some(resolved.into()), false, Some(explicit_self_ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_where_predicate<'b>(
|
pub(crate) fn lower_where_predicate<'b>(
|
||||||
|
@ -1041,7 +1036,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
let mut trait_ref = None;
|
let mut trait_ref = None;
|
||||||
let clause = match bound.as_ref() {
|
let clause = match bound.as_ref() {
|
||||||
TypeBound::Path(path, TraitBoundModifier::None) => {
|
TypeBound::Path(path, TraitBoundModifier::None) => {
|
||||||
trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
|
trait_ref = self.lower_trait_ref_from_path(path, self_ty);
|
||||||
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
||||||
}
|
}
|
||||||
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
|
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
|
||||||
|
@ -1053,7 +1048,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
// `?Sized` has no of them.
|
// `?Sized` has no of them.
|
||||||
// If we got another trait here ignore the bound completely.
|
// If we got another trait here ignore the bound completely.
|
||||||
let trait_id = self
|
let trait_id = self
|
||||||
.lower_trait_ref_from_path(path, Some(self_ty.clone()))
|
.lower_trait_ref_from_path(path, self_ty.clone())
|
||||||
.map(|trait_ref| trait_ref.hir_trait_id());
|
.map(|trait_ref| trait_ref.hir_trait_id());
|
||||||
if trait_id == sized_trait {
|
if trait_id == sized_trait {
|
||||||
self.unsized_types.borrow_mut().insert(self_ty);
|
self.unsized_types.borrow_mut().insert(self_ty);
|
||||||
|
@ -1062,7 +1057,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
}
|
}
|
||||||
TypeBound::ForLifetime(_, path) => {
|
TypeBound::ForLifetime(_, path) => {
|
||||||
// FIXME Don't silently drop the hrtb lifetimes here
|
// FIXME Don't silently drop the hrtb lifetimes here
|
||||||
trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
|
trait_ref = self.lower_trait_ref_from_path(path, self_ty);
|
||||||
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
||||||
}
|
}
|
||||||
TypeBound::Lifetime(l) => {
|
TypeBound::Lifetime(l) => {
|
||||||
|
@ -2126,7 +2121,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
|
||||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||||
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
|
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
|
||||||
let target_trait = impl_data.target_trait.as_ref()?;
|
let target_trait = impl_data.target_trait.as_ref()?;
|
||||||
Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
|
Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn return_type_impl_traits(
|
pub(crate) fn return_type_impl_traits(
|
||||||
|
|
|
@ -421,9 +421,25 @@ impl MirEvalError {
|
||||||
}
|
}
|
||||||
MirEvalError::MirLowerError(func, err) => {
|
MirEvalError::MirLowerError(func, err) => {
|
||||||
let function_name = db.function_data(*func);
|
let function_name = db.function_data(*func);
|
||||||
|
let self_ = match func.lookup(db.upcast()).container {
|
||||||
|
ItemContainerId::ImplId(impl_id) => Some({
|
||||||
|
let generics = crate::generics::generics(db.upcast(), impl_id.into());
|
||||||
|
let substs = generics.placeholder_subst(db);
|
||||||
|
db.impl_self_ty(impl_id)
|
||||||
|
.substitute(Interner, &substs)
|
||||||
|
.display(db, edition)
|
||||||
|
.to_string()
|
||||||
|
}),
|
||||||
|
ItemContainerId::TraitId(it) => {
|
||||||
|
Some(db.trait_data(it).name.display(db.upcast(), edition).to_string())
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"MIR lowering for function `{}` ({:?}) failed due:",
|
"MIR lowering for function `{}{}{}` ({:?}) failed due:",
|
||||||
|
self_.as_deref().unwrap_or_default(),
|
||||||
|
if self_.is_some() { "::" } else { "" },
|
||||||
function_name.name.display(db.upcast(), edition),
|
function_name.name.display(db.upcast(), edition),
|
||||||
func
|
func
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -94,7 +94,8 @@ pub enum MirLowerError {
|
||||||
UnresolvedField,
|
UnresolvedField,
|
||||||
UnsizedTemporary(Ty),
|
UnsizedTemporary(Ty),
|
||||||
MissingFunctionDefinition(DefWithBodyId, ExprId),
|
MissingFunctionDefinition(DefWithBodyId, ExprId),
|
||||||
TypeMismatch(Option<TypeMismatch>),
|
TypeMismatch(TypeMismatch),
|
||||||
|
HasErrors,
|
||||||
/// This should never happen. Type mismatch should catch everything.
|
/// This should never happen. Type mismatch should catch everything.
|
||||||
TypeError(&'static str),
|
TypeError(&'static str),
|
||||||
NotSupported(String),
|
NotSupported(String),
|
||||||
|
@ -179,15 +180,13 @@ impl MirLowerError {
|
||||||
body.pretty_print_expr(db.upcast(), *owner, *it, edition)
|
body.pretty_print_expr(db.upcast(), *owner, *it, edition)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
MirLowerError::TypeMismatch(e) => match e {
|
MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
|
||||||
Some(e) => writeln!(
|
MirLowerError::TypeMismatch(e) => writeln!(
|
||||||
f,
|
f,
|
||||||
"Type mismatch: Expected {}, found {}",
|
"Type mismatch: Expected {}, found {}",
|
||||||
e.expected.display(db, edition),
|
e.expected.display(db, edition),
|
||||||
e.actual.display(db, edition),
|
e.actual.display(db, edition),
|
||||||
)?,
|
)?,
|
||||||
None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?,
|
|
||||||
},
|
|
||||||
MirLowerError::GenericArgNotProvided(id, subst) => {
|
MirLowerError::GenericArgNotProvided(id, subst) => {
|
||||||
let parent = id.parent;
|
let parent = id.parent;
|
||||||
let param = &db.generic_params(parent)[id.local_id];
|
let param = &db.generic_params(parent)[id.local_id];
|
||||||
|
@ -2184,7 +2183,7 @@ pub fn lower_to_mir(
|
||||||
root_expr: ExprId,
|
root_expr: ExprId,
|
||||||
) -> Result<MirBody> {
|
) -> Result<MirBody> {
|
||||||
if infer.has_errors {
|
if infer.has_errors {
|
||||||
return Err(MirLowerError::TypeMismatch(None));
|
return Err(MirLowerError::HasErrors);
|
||||||
}
|
}
|
||||||
let mut ctx = MirLowerCtx::new(db, owner, body, infer);
|
let mut ctx = MirLowerCtx::new(db, owner, body, infer);
|
||||||
// 0 is return local
|
// 0 is return local
|
||||||
|
|
|
@ -831,7 +831,7 @@ fn main() {
|
||||||
//- minicore: sized
|
//- minicore: sized
|
||||||
fn main() {
|
fn main() {
|
||||||
_ = ((), ()) as ();
|
_ = ((), ()) as ();
|
||||||
//^^^^^^^^^^^^^^ error: non-primitive cast: `(_, _)` as `()`
|
//^^^^^^^^^^^^^^ error: non-primitive cast: `((), ())` as `()`
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
|
@ -95,8 +95,10 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
|
||||||
fn test_crate(&self) -> CrateId {
|
fn test_crate(&self) -> CrateId {
|
||||||
let crate_graph = self.crate_graph();
|
let crate_graph = self.crate_graph();
|
||||||
let mut it = crate_graph.iter();
|
let mut it = crate_graph.iter();
|
||||||
let res = it.next().unwrap();
|
let mut res = it.next().unwrap();
|
||||||
assert!(it.next().is_none());
|
while crate_graph[res].origin.is_lang() {
|
||||||
|
res = it.next().unwrap();
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,7 @@ pub mod default {
|
||||||
macro_rules! impl_default {
|
macro_rules! impl_default {
|
||||||
($v:literal; $($t:ty)*) => {
|
($v:literal; $($t:ty)*) => {
|
||||||
$(
|
$(
|
||||||
impl const Default for $t {
|
impl Default for $t {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
$v
|
$v
|
||||||
}
|
}
|
||||||
|
@ -686,7 +686,7 @@ pub mod ops {
|
||||||
// endregion:fn
|
// endregion:fn
|
||||||
// region:try
|
// region:try
|
||||||
mod try_ {
|
mod try_ {
|
||||||
use super::super::convert::Infallible;
|
use crate::convert::Infallible;
|
||||||
|
|
||||||
pub enum ControlFlow<B, C = ()> {
|
pub enum ControlFlow<B, C = ()> {
|
||||||
#[lang = "Continue"]
|
#[lang = "Continue"]
|
||||||
|
@ -756,7 +756,7 @@ pub mod ops {
|
||||||
// endregion:option
|
// endregion:option
|
||||||
// region:result
|
// region:result
|
||||||
// region:from
|
// region:from
|
||||||
use super::super::convert::From;
|
use crate::convert::From;
|
||||||
|
|
||||||
impl<T, E> Try for Result<T, E> {
|
impl<T, E> Try for Result<T, E> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
@ -777,7 +777,7 @@ pub mod ops {
|
||||||
impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {
|
impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {
|
||||||
fn from_residual(residual: Result<Infallible, E>) -> Self {
|
fn from_residual(residual: Result<Infallible, E>) -> Self {
|
||||||
match residual {
|
match residual {
|
||||||
Err(e) => Err(From::from(e)),
|
Err(e) => Err(F::from(e)),
|
||||||
Ok(_) => loop {},
|
Ok(_) => loop {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue