mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-26 13:54:06 +00:00
add projection to infer for loop variable
This commit is contained in:
parent
fee552d487
commit
f7cd40d830
@ -86,6 +86,11 @@ impl Name {
|
|||||||
"Self" => KnownName::SelfType,
|
"Self" => KnownName::SelfType,
|
||||||
"self" => KnownName::SelfParam,
|
"self" => KnownName::SelfParam,
|
||||||
"macro_rules" => KnownName::MacroRules,
|
"macro_rules" => KnownName::MacroRules,
|
||||||
|
|
||||||
|
"std" => KnownName::Std,
|
||||||
|
"iter" => KnownName::Iter,
|
||||||
|
"IntoIterator" => KnownName::IntoIterator,
|
||||||
|
"Item" => KnownName::Item,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(name)
|
Some(name)
|
||||||
@ -157,6 +162,11 @@ pub(crate) enum KnownName {
|
|||||||
SelfParam,
|
SelfParam,
|
||||||
|
|
||||||
MacroRules,
|
MacroRules,
|
||||||
|
|
||||||
|
Std,
|
||||||
|
Iter,
|
||||||
|
IntoIterator,
|
||||||
|
Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsName for KnownName {
|
impl AsName for KnownName {
|
||||||
@ -182,6 +192,10 @@ impl AsName for KnownName {
|
|||||||
KnownName::SelfType => "Self",
|
KnownName::SelfType => "Self",
|
||||||
KnownName::SelfParam => "self",
|
KnownName::SelfParam => "self",
|
||||||
KnownName::MacroRules => "macro_rules",
|
KnownName::MacroRules => "macro_rules",
|
||||||
|
KnownName::Std => "std",
|
||||||
|
KnownName::Iter => "iter",
|
||||||
|
KnownName::IntoIterator => "IntoIterator",
|
||||||
|
KnownName::Item => "Item",
|
||||||
};
|
};
|
||||||
Name::new(s.into())
|
Name::new(s.into())
|
||||||
}
|
}
|
||||||
|
@ -28,24 +28,28 @@ use test_utils::tested_by;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
autoderef, method_resolution, op, primitive,
|
autoderef, method_resolution, op, primitive,
|
||||||
traits::{Guidance, Obligation, Solution},
|
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
|
||||||
ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypableDef, TypeCtor,
|
ApplicationTy, CallableDef, ProjectionTy, Substs, TraitRef, Ty, TypableDef, TypeCtor,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::VariantDef,
|
adt::VariantDef,
|
||||||
|
code_model::{ModuleDef::Trait, TypeAlias},
|
||||||
diagnostics::DiagnosticSink,
|
diagnostics::DiagnosticSink,
|
||||||
expr::{
|
expr::{
|
||||||
self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, FieldPat, Literal, Pat,
|
self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, FieldPat, Literal, Pat,
|
||||||
PatId, Statement, UnaryOp,
|
PatId, Statement, UnaryOp,
|
||||||
},
|
},
|
||||||
generics::{GenericParams, HasGenericParams},
|
generics::{GenericParams, HasGenericParams},
|
||||||
nameres::Namespace,
|
nameres::{Namespace, PerNs},
|
||||||
path::{GenericArg, GenericArgs},
|
path::{GenericArg, GenericArgs, PathKind, PathSegment},
|
||||||
resolve::{Resolution, Resolver},
|
resolve::{
|
||||||
|
Resolution::{self, Def},
|
||||||
|
Resolver,
|
||||||
|
},
|
||||||
ty::infer::diagnostics::InferenceDiagnostic,
|
ty::infer::diagnostics::InferenceDiagnostic,
|
||||||
type_ref::{Mutability, TypeRef},
|
type_ref::{Mutability, TypeRef},
|
||||||
AdtDef, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, ModuleDef, Name, Path,
|
AdtDef, AsName, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, KnownName,
|
||||||
StructField,
|
ModuleDef, Name, Path, StructField,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod unify;
|
mod unify;
|
||||||
@ -323,34 +327,53 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||||||
fn resolve_obligations_as_possible(&mut self) {
|
fn resolve_obligations_as_possible(&mut self) {
|
||||||
let obligations = mem::replace(&mut self.obligations, Vec::new());
|
let obligations = mem::replace(&mut self.obligations, Vec::new());
|
||||||
for obligation in obligations {
|
for obligation in obligations {
|
||||||
let (solution, canonicalized) = match &obligation {
|
match &obligation {
|
||||||
Obligation::Trait(tr) => {
|
Obligation::Trait(tr) => {
|
||||||
let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
|
let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
|
||||||
(
|
let solution = self
|
||||||
self.db.implements(
|
.db
|
||||||
self.resolver.krate().unwrap(),
|
.implements(self.resolver.krate().unwrap(), canonicalized.value.clone());
|
||||||
canonicalized.value.clone(),
|
match solution {
|
||||||
),
|
Some(Solution::Unique(substs)) => {
|
||||||
canonicalized,
|
canonicalized.apply_solution(self, substs.0);
|
||||||
)
|
}
|
||||||
|
Some(Solution::Ambig(Guidance::Definite(substs))) => {
|
||||||
|
canonicalized.apply_solution(self, substs.0);
|
||||||
|
self.obligations.push(obligation);
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
// FIXME use this when trying to resolve everything at the end
|
||||||
|
self.obligations.push(obligation);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// FIXME obligation cannot be fulfilled => diagnostic
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Obligation::Projection(pr) => {
|
||||||
|
let canonicalized = self.canonicalizer().canonicalize_projection(pr.clone());
|
||||||
|
let solution = self
|
||||||
|
.db
|
||||||
|
.normalize(self.resolver.krate().unwrap(), canonicalized.value.clone());
|
||||||
|
|
||||||
|
match solution {
|
||||||
|
Some(Solution::Unique(substs)) => {
|
||||||
|
canonicalized.apply_solution(self, substs.0);
|
||||||
|
}
|
||||||
|
Some(Solution::Ambig(Guidance::Definite(substs))) => {
|
||||||
|
canonicalized.apply_solution(self, substs.0);
|
||||||
|
self.obligations.push(obligation);
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
// FIXME use this when trying to resolve everything at the end
|
||||||
|
self.obligations.push(obligation);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// FIXME obligation cannot be fulfilled => diagnostic
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match solution {
|
|
||||||
Some(Solution::Unique(substs)) => {
|
|
||||||
canonicalized.apply_solution(self, substs.0);
|
|
||||||
}
|
|
||||||
Some(Solution::Ambig(Guidance::Definite(substs))) => {
|
|
||||||
canonicalized.apply_solution(self, substs.0);
|
|
||||||
self.obligations.push(obligation);
|
|
||||||
}
|
|
||||||
Some(_) => {
|
|
||||||
// FIXME use this when trying to resolve everything at the end
|
|
||||||
self.obligations.push(obligation);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// FIXME obligation cannot be fulfilled => diagnostic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -967,8 +990,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||||||
Ty::unit()
|
Ty::unit()
|
||||||
}
|
}
|
||||||
Expr::For { iterable, body, pat } => {
|
Expr::For { iterable, body, pat } => {
|
||||||
let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
|
let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
|
||||||
self.infer_pat(*pat, &Ty::Unknown, BindingMode::default());
|
|
||||||
|
let pat_ty = match self.resolve_into_iter_item() {
|
||||||
|
Some(into_iter_item_alias) => {
|
||||||
|
let pat_ty = self.new_type_var();
|
||||||
|
let projection = ProjectionPredicate {
|
||||||
|
ty: pat_ty.clone(),
|
||||||
|
projection_ty: ProjectionTy {
|
||||||
|
associated_ty: into_iter_item_alias,
|
||||||
|
parameters: vec![iterable_ty].into(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.obligations.push(Obligation::Projection(projection));
|
||||||
|
self.resolve_ty_as_possible(&mut vec![], pat_ty)
|
||||||
|
}
|
||||||
|
None => Ty::Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.infer_pat(*pat, &pat_ty, BindingMode::default());
|
||||||
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
||||||
Ty::unit()
|
Ty::unit()
|
||||||
}
|
}
|
||||||
@ -1301,6 +1341,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||||||
fn infer_body(&mut self) {
|
fn infer_body(&mut self) {
|
||||||
self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone()));
|
self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
|
||||||
|
let into_iter_path = Path {
|
||||||
|
kind: PathKind::Abs,
|
||||||
|
segments: vec![
|
||||||
|
PathSegment { name: KnownName::Std.as_name(), args_and_bindings: None },
|
||||||
|
PathSegment { name: KnownName::Iter.as_name(), args_and_bindings: None },
|
||||||
|
PathSegment { name: KnownName::IntoIterator.as_name(), args_and_bindings: None },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() {
|
||||||
|
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
||||||
|
Some(trait_.associated_type_by_name(self.db, KnownName::Item.as_name())?)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The ID of a type variable.
|
/// The ID of a type variable.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use super::InferenceContext;
|
use super::InferenceContext;
|
||||||
use crate::db::HirDatabase;
|
use crate::db::HirDatabase;
|
||||||
use crate::ty::{Canonical, InferTy, TraitRef, Ty};
|
use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty};
|
||||||
|
|
||||||
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
|
pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
|
||||||
@ -86,6 +86,25 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy {
|
||||||
|
let params = projection_ty
|
||||||
|
.parameters
|
||||||
|
.iter()
|
||||||
|
.map(|ty| self.do_canonicalize_ty(ty.clone()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: params.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_canonicalize_projection_predicate(
|
||||||
|
&mut self,
|
||||||
|
projection: ProjectionPredicate,
|
||||||
|
) -> ProjectionPredicate {
|
||||||
|
let ty = self.do_canonicalize_ty(projection.ty);
|
||||||
|
let projection_ty = self.do_canonicalize_projection_ty(projection.projection_ty);
|
||||||
|
|
||||||
|
ProjectionPredicate { ty, projection_ty }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
|
pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
|
||||||
let result = self.do_canonicalize_ty(ty);
|
let result = self.do_canonicalize_ty(ty);
|
||||||
self.into_canonicalized(result)
|
self.into_canonicalized(result)
|
||||||
@ -95,6 +114,14 @@ where
|
|||||||
let result = self.do_canonicalize_trait_ref(trait_ref);
|
let result = self.do_canonicalize_trait_ref(trait_ref);
|
||||||
self.into_canonicalized(result)
|
self.into_canonicalized(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn canonicalize_projection(
|
||||||
|
mut self,
|
||||||
|
projection: ProjectionPredicate,
|
||||||
|
) -> Canonicalized<ProjectionPredicate> {
|
||||||
|
let result = self.do_canonicalize_projection_predicate(projection);
|
||||||
|
self.into_canonicalized(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Canonicalized<T> {
|
impl<T> Canonicalized<T> {
|
||||||
|
@ -20,6 +20,42 @@ use crate::{
|
|||||||
// against snapshots of the expected results using insta. Use cargo-insta to
|
// against snapshots of the expected results using insta. Use cargo-insta to
|
||||||
// update the snapshots.
|
// update the snapshots.
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_for_loop() {
|
||||||
|
let (mut db, pos) = MockDatabase::with_position(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Vec<T> {}
|
||||||
|
impl<T> Vec<T> {
|
||||||
|
fn new() -> Self { Vec {} }
|
||||||
|
fn push(&mut self, t: T) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ::std::iter::IntoIterator for Vec<T> {
|
||||||
|
type Item=T;
|
||||||
|
}
|
||||||
|
fn test() {
|
||||||
|
let v = Vec::new();
|
||||||
|
v.push("foo");
|
||||||
|
for x in v {
|
||||||
|
x<|>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /lib.rs
|
||||||
|
mod iter {
|
||||||
|
trait IntoIterator {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
db.set_crate_graph_from_fixture(crate_graph! {
|
||||||
|
"main": ("/main.rs", ["std"]),
|
||||||
|
"std": ("/lib.rs", []),
|
||||||
|
});
|
||||||
|
assert_eq!("&str", type_at_pos(&db, pos));
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_basics() {
|
fn infer_basics() {
|
||||||
assert_snapshot_matches!(
|
assert_snapshot_matches!(
|
||||||
|
@ -75,7 +75,7 @@ pub enum Obligation {
|
|||||||
/// Prove that a certain type implements a trait (the type is the `Self` type
|
/// Prove that a certain type implements a trait (the type is the `Self` type
|
||||||
/// parameter to the `TraitRef`).
|
/// parameter to the `TraitRef`).
|
||||||
Trait(TraitRef),
|
Trait(TraitRef),
|
||||||
// Projection(ProjectionPredicate),
|
Projection(ProjectionPredicate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obligation {
|
impl Obligation {
|
||||||
|
Loading…
Reference in New Issue
Block a user