1845: Closure types r=flodiebold a=flodiebold

This adds types for closures and makes them implement the `Fn` traits (we don't currently care or try to infer `Fn` vs. `FnMut` vs. `FnOnce`; this would require move analysis, I think).

This requires some changes in Chalk; one is that we need to know the self type when asked for impls, so we can synthesize `Fn` trait impls for closures; but also there's a problem that prevents us from normalizing the closure output type correctly that I _think_ will be fixed on the Chalk side (basically, we ask too early and try to solve `Normalize(<?1 as FnOnce<(u32,)>>::Output => ?0)` -- note the variable in the self type -- and instead of an ambiguous answer, we get back that it can't be solved, so we don't try again. Niko mentioned he's making all goals where the self type is unconstrained flounder, which I think would mean this would be ambiguous).

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2019-09-24 21:12:26 +00:00 committed by GitHub
commit c7420ddaaa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 385 additions and 72 deletions

View file

@ -551,6 +551,14 @@ impl DefWithBody {
DefWithBody::Static(s) => s.resolver(db),
}
}
pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
match self {
DefWithBody::Const(c) => c.krate(db),
DefWithBody::Function(f) => f.krate(db),
DefWithBody::Static(s) => s.krate(db),
}
}
}
pub trait HasBody: Copy {
@ -671,6 +679,10 @@ impl Function {
self.id.module(db)
}
pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
self.module(db).krate(db)
}
pub fn name(self, db: &impl HirDatabase) -> Name {
self.data(db).name.clone()
}
@ -745,6 +757,10 @@ impl Const {
self.id.module(db)
}
pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
self.module(db).krate(db)
}
pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
db.const_data(self)
}
@ -824,6 +840,10 @@ impl Static {
self.id.module(db)
}
pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
self.module(db).krate(db)
}
pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
db.static_data(self)
}

View file

@ -13,8 +13,8 @@ use crate::{
nameres::{CrateDefMap, ImportSourceMap, Namespace, RawItems},
traits::TraitData,
ty::{
method_resolution::CrateImplBlocks, CallableDef, FnSig, GenericPredicate, InferenceResult,
Substs, Ty, TypableDef, TypeCtor,
method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate,
InferenceResult, Substs, Ty, TypableDef, TypeCtor,
},
type_alias::TypeAliasData,
AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData,
@ -50,7 +50,7 @@ pub trait InternDatabase: SourceDatabase {
#[salsa::interned]
fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
#[salsa::interned]
fn intern_impl_block(&self, impl_block: ImplBlock) -> ids::GlobalImplId;
fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId;
}
/// This database has access to source code, so queries here are not really

View file

@ -16,7 +16,10 @@ use std::ops::Deref;
use std::sync::Arc;
use std::{fmt, mem};
use crate::{db::HirDatabase, type_ref::Mutability, Adt, GenericParams, Name, Trait, TypeAlias};
use crate::{
db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, DefWithBody, GenericParams, Name,
Trait, TypeAlias,
};
use display::{HirDisplay, HirFormatter};
pub(crate) use autoderef::autoderef;
@ -100,6 +103,12 @@ pub enum TypeCtor {
/// couldn't find a better representation. In that case, we generate
/// an **application type** like `(Iterator::Item)<T>`.
AssociatedType(TypeAlias),
/// The type of a specific closure.
///
/// The closure signature is stored in a `FnPtr` type in the first type
/// parameter.
Closure { def: DefWithBody, expr: ExprId },
}
/// A nominal type with (maybe 0) type parameters. This might be a primitive
@ -481,6 +490,10 @@ impl Ty {
let sig = db.callable_item_signature(def);
Some(sig.subst(&a_ty.parameters))
}
TypeCtor::Closure { .. } => {
let sig_param = &a_ty.parameters[0];
sig_param.callable_sig(db)
}
_ => None,
},
_ => None,
@ -720,6 +733,14 @@ impl HirDisplay for ApplicationTy {
write!(f, ">")?;
}
}
TypeCtor::Closure { .. } => {
let sig = self.parameters[0]
.callable_sig(f.db)
.expect("first closure parameter should contain signature");
write!(f, "|")?;
f.write_joined(sig.params(), ", ")?;
write!(f, "| -> {}", sig.ret().display(f.db))?;
}
}
Ok(())
}

View file

@ -790,11 +790,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
};
self.unify(&expected_receiver_ty, &actual_receiver_ty);
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
for (arg, param_ty) in args.iter().zip(param_iter) {
let param_ty = self.normalize_associated_types_in(param_ty);
self.infer_expr(*arg, &Expectation::has_type(param_ty));
}
self.check_call_arguments(args, &param_tys);
let ret_ty = self.normalize_associated_types_in(ret_ty);
ret_ty
}
@ -885,18 +881,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Expr::Lambda { body, args, arg_types } => {
assert_eq!(args.len(), arg_types.len());
let mut sig_tys = Vec::new();
for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
let expected = if let Some(type_ref) = arg_type {
self.make_ty(type_ref)
} else {
Ty::Unknown
};
self.infer_pat(*arg_pat, &expected, BindingMode::default());
let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
sig_tys.push(arg_ty);
}
// FIXME: infer lambda type etc.
let _body_ty = self.infer_expr(*body, &Expectation::none());
Ty::Unknown
// add return type
let ret_ty = self.new_type_var();
sig_tys.push(ret_ty.clone());
let sig_ty = Ty::apply(
TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
sig_tys.into(),
);
let closure_ty = Ty::apply_one(
TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
sig_ty,
);
// Eagerly try to relate the closure type with the expected
// type, otherwise we often won't have enough information to
// infer the body.
self.coerce(&closure_ty, &expected.ty);
self.infer_expr(*body, &Expectation::has_type(ret_ty));
closure_ty
}
Expr::Call { callee, args } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none());
@ -909,11 +924,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
};
self.register_obligations_for_call(&callee_ty);
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
for (arg, param_ty) in args.iter().zip(param_iter) {
let param_ty = self.normalize_associated_types_in(param_ty);
self.infer_expr(*arg, &Expectation::has_type(param_ty));
}
self.check_call_arguments(args, &param_tys);
let ret_ty = self.normalize_associated_types_in(ret_ty);
ret_ty
}
@ -1255,6 +1266,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty
}
fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) {
// Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
// We do this in a pretty awful way: first we type-check any arguments
// that are not closures, then we type-check the closures. This is so
// that we have more information about the types of arguments when we
// type-check the functions. This isn't really the right way to do this.
for &check_closures in &[false, true] {
let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
for (&arg, param_ty) in args.iter().zip(param_iter) {
let is_closure = match &self.body[arg] {
Expr::Lambda { .. } => true,
_ => false,
};
if is_closure != check_closures {
continue;
}
let param_ty = self.normalize_associated_types_in(param_ty);
self.infer_expr(arg, &Expectation::has_type(param_ty));
}
}
}
fn collect_const(&mut self, data: &ConstData) {
self.return_ty = self.make_ty(data.type_ref());
}

View file

@ -1077,7 +1077,6 @@ fn test(x: &i32) {
}
"#),
@r###"
[9; 10) 'x': &i32
[18; 369) '{ ...o_x; }': ()
[28; 29) 'y': &i32
@ -1107,8 +1106,8 @@ fn test(x: &i32) {
[177; 205) '{ ... }': ()
[191; 192) 'h': {unknown}
[195; 198) 'val': {unknown}
[215; 221) 'lambda': {unknown}
[224; 256) '|a: u6...b; c }': {unknown}
[215; 221) 'lambda': |u64, u64, i32| -> i32
[224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32
[225; 226) 'a': u64
[233; 234) 'b': u64
[236; 237) 'c': i32
@ -2836,12 +2835,11 @@ fn test() -> u64 {
}
"#),
@r###"
[44; 102) '{ ...0(2) }': u64
[54; 55) 'a': S
[58; 59) 'S': S(fn(u32) -> u64) -> S
[58; 68) 'S(|i| 2*i)': S
[60; 67) '|i| 2*i': fn(u32) -> u64
[60; 67) '|i| 2*i': |i32| -> i32
[61; 62) 'i': i32
[64; 65) '2': i32
[64; 67) '2*i': i32
@ -3802,13 +3800,13 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
[296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
[296; 302) 'get(x)': {unknown}
[300; 301) 'x': T
[308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
[308; 312) 'get2': fn get2<{unknown}, T>(T) -> U
[308; 315) 'get2(x)': {unknown}
[313; 314) 'x': T
[321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
[321; 327) 'get(y)': {unknown}
[325; 326) 'y': impl Trait<Type = i64>
[333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
[333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U
[333; 340) 'get2(y)': {unknown}
[338; 339) 'y': impl Trait<Type = i64>
[346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
@ -3992,49 +3990,50 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
fn closure_1() {
assert_snapshot!(
infer(r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
enum Option<T> { Some(T), None }
impl<T> Option<T> {
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {}
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
}
fn test() {
let x = Option::Some(1i32);
let x = Option::Some(1u32);
x.map(|v| v + 1);
x.map(|_v| 1u64);
let y: Option<i64> = x.map(|_v| 1);
}
"#),
@r###"
[128; 132) 'self': Option<T>
[134; 135) 'f': F
[145; 147) '{}': ()
[161; 280) '{ ... 1); }': ()
[171; 172) 'x': Option<i32>
[175; 187) 'Option::Some': Some<i32>(T) -> Option<T>
[175; 193) 'Option...(1i32)': Option<i32>
[188; 192) '1i32': i32
[199; 200) 'x': Option<i32>
[199; 215) 'x.map(...v + 1)': {unknown}
[205; 214) '|v| v + 1': {unknown}
[206; 207) 'v': {unknown}
[209; 210) 'v': {unknown}
[209; 214) 'v + 1': i32
[213; 214) '1': i32
[221; 222) 'x': Option<i32>
[221; 237) 'x.map(... 1u64)': {unknown}
[227; 236) '|_v| 1u64': {unknown}
[228; 230) '_v': {unknown}
[232; 236) '1u64': u64
[247; 248) 'y': Option<i64>
[264; 265) 'x': Option<i32>
[264; 277) 'x.map(|_v| 1)': Option<i64>
[270; 276) '|_v| 1': {unknown}
[271; 273) '_v': {unknown}
[275; 276) '1': i32
[148; 152) 'self': Option<T>
[154; 155) 'f': F
[173; 175) '{}': ()
[189; 308) '{ ... 1); }': ()
[199; 200) 'x': Option<u32>
[203; 215) 'Option::Some': Some<u32>(T) -> Option<T>
[203; 221) 'Option...(1u32)': Option<u32>
[216; 220) '1u32': u32
[227; 228) 'x': Option<u32>
[227; 243) 'x.map(...v + 1)': Option<u32>
[233; 242) '|v| v + 1': |u32| -> u32
[234; 235) 'v': u32
[237; 238) 'v': u32
[237; 242) 'v + 1': u32
[241; 242) '1': u32
[249; 250) 'x': Option<u32>
[249; 265) 'x.map(... 1u64)': Option<u64>
[255; 264) '|_v| 1u64': |u32| -> u64
[256; 258) '_v': u32
[260; 264) '1u64': u64
[275; 276) 'y': Option<i64>
[292; 293) 'x': Option<u32>
[292; 305) 'x.map(|_v| 1)': Option<i64>
[298; 304) '|_v| 1': |u32| -> i64
[299; 301) '_v': u32
[303; 304) '1': i64
"###
);
}
@ -4060,17 +4059,17 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
[85; 86) 'f': F
[85; 89) 'f(1)': {unknown}
[87; 88) '1': i32
[99; 100) 'g': {unknown}
[103; 112) '|v| v + 1': {unknown}
[104; 105) 'v': {unknown}
[107; 108) 'v': {unknown}
[99; 100) 'g': |u64| -> i32
[103; 112) '|v| v + 1': |u64| -> i32
[104; 105) 'v': u64
[107; 108) 'v': u64
[107; 112) 'v + 1': i32
[111; 112) '1': i32
[118; 119) 'g': {unknown}
[118; 125) 'g(1u64)': {unknown}
[118; 119) 'g': |u64| -> i32
[118; 125) 'g(1u64)': i32
[120; 124) '1u64': u64
[135; 136) 'h': {unknown}
[139; 152) '|v| 1u128 + v': {unknown}
[135; 136) 'h': |u128| -> u128
[139; 152) '|v| 1u128 + v': |u128| -> u128
[140; 141) 'v': u128
[143; 148) '1u128': u128
[143; 152) '1u128 + v': u128
@ -4079,6 +4078,86 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
);
}
#[test]
fn closure_as_argument_inference_order() {
assert_snapshot!(
infer(r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
struct S;
impl S {
fn method(self) -> u64;
fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
}
fn test() {
let x1 = foo1(S, |s| s.method());
let x2 = foo2(|s| s.method(), S);
let x3 = S.foo1(S, |s| s.method());
let x4 = S.foo2(|s| s.method(), S);
}
"#),
@r###"
[95; 96) 'x': T
[101; 102) 'f': F
[112; 114) '{}': ()
[148; 149) 'f': F
[154; 155) 'x': T
[165; 167) '{}': ()
[202; 206) 'self': S
[254; 258) 'self': S
[260; 261) 'x': T
[266; 267) 'f': F
[277; 279) '{}': ()
[317; 321) 'self': S
[323; 324) 'f': F
[329; 330) 'x': T
[340; 342) '{}': ()
[356; 515) '{ ... S); }': ()
[366; 368) 'x1': u64
[371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U
[371; 394) 'foo1(S...hod())': u64
[376; 377) 'S': S
[379; 393) '|s| s.method()': |S| -> u64
[380; 381) 's': S
[383; 384) 's': S
[383; 393) 's.method()': u64
[404; 406) 'x2': u64
[409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U
[409; 432) 'foo2(|...(), S)': u64
[414; 428) '|s| s.method()': |S| -> u64
[415; 416) 's': S
[418; 419) 's': S
[418; 428) 's.method()': u64
[430; 431) 'S': S
[442; 444) 'x3': u64
[447; 448) 'S': S
[447; 472) 'S.foo1...hod())': u64
[454; 455) 'S': S
[457; 471) '|s| s.method()': |S| -> u64
[458; 459) 's': S
[461; 462) 's': S
[461; 471) 's.method()': u64
[482; 484) 'x4': u64
[487; 488) 'S': S
[487; 512) 'S.foo2...(), S)': u64
[494; 508) '|s| s.method()': |S| -> u64
[495; 496) 's': S
[498; 499) 's': S
[498; 508) 's.method()': u64
[510; 511) 'S': S
"###
);
}
#[test]
fn unselected_projection_in_trait_env_1() {
let t = type_at(

View file

@ -9,7 +9,7 @@ use ra_prof::profile;
use rustc_hash::FxHashSet;
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait};
use self::chalk::{from_chalk, ToChalk};
@ -173,6 +173,14 @@ pub(crate) fn trait_solve_query(
) -> Option<Solution> {
let _p = profile("trait_solve_query");
debug!("trait_solve_query({})", goal.value.value.display(db));
if let Obligation::Projection(pred) = &goal.value.value {
if let Ty::Bound(_) = &pred.projection_ty.parameters[0] {
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
return Some(Solution::Ambig(Guidance::Unknown));
}
}
let canonical = goal.to_chalk(db).cast();
// We currently don't deal with universes (I think / hope they're not yet
// relevant for our use cases?)
@ -252,3 +260,37 @@ pub enum Guidance {
/// There's no useful information to feed back to type inference
Unknown,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
FnOnce,
FnMut,
Fn,
}
impl FnTrait {
fn lang_item_name(self) -> &'static str {
match self {
FnTrait::FnOnce => "fn_once",
FnTrait::FnMut => "fn_mut",
FnTrait::Fn => "fn",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClosureFnTraitImplData {
def: DefWithBody,
expr: ExprId,
fn_trait: FnTrait,
}
/// An impl. Usually this comes from an impl block, but some built-in types get
/// synthetic impls.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Impl {
/// A normal impl from an impl block.
ImplBlock(ImplBlock),
/// Closure types implement the Fn traits synthetically.
ClosureFnTraitImpl(ClosureFnTraitImplData),
}

View file

@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
use ra_db::salsa::{InternId, InternKey};
use test_utils::tested_by;
use super::{Canonical, ChalkContext, Obligation};
use super::{Canonical, ChalkContext, Impl, Obligation};
use crate::{
db::HirDatabase,
generics::GenericDef,
@ -111,7 +111,7 @@ impl ToChalk for Ty {
}
chalk_ir::Ty::ForAll(_) => unimplemented!(),
chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown,
}
}
}
@ -175,15 +175,15 @@ impl ToChalk for TypeCtor {
}
}
impl ToChalk for ImplBlock {
impl ToChalk for Impl {
type Chalk = chalk_ir::ImplId;
fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
db.intern_impl_block(self).into()
db.intern_impl(self).into()
}
fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
db.lookup_intern_impl_block(impl_id.into())
fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl {
db.lookup_intern_impl(impl_id.into())
}
}
@ -388,19 +388,36 @@ where
fn impls_for_trait(
&self,
trait_id: chalk_ir::TraitId,
_parameters: &[Parameter],
parameters: &[Parameter],
) -> Vec<ImplId> {
debug!("impls_for_trait {:?}", trait_id);
if trait_id == UNKNOWN_TRAIT {
return Vec::new();
}
let trait_: Trait = from_chalk(self.db, trait_id);
let result: Vec<_> = self
let mut result: Vec<_> = self
.db
.impls_for_trait(self.krate, trait_)
.iter()
.map(|impl_block| impl_block.to_chalk(self.db))
.copied()
.map(Impl::ImplBlock)
.map(|impl_| impl_.to_chalk(self.db))
.collect();
let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone());
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
for &fn_trait in
[super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
{
if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
if trait_ == actual_trait {
let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
}
}
}
}
debug!("impls_for_trait returned {} impls", result.len());
result
}
@ -571,6 +588,10 @@ pub(crate) fn struct_datum_query(
type_alias.krate(db) != Some(krate),
)
}
TypeCtor::Closure { def, .. } => {
let upstream = def.krate(db) != Some(krate);
(1, vec![], upstream)
}
};
let flags = chalk_rust_ir::StructFlags {
upstream,
@ -598,7 +619,21 @@ pub(crate) fn impl_datum_query(
) -> Arc<ImplDatum> {
let _p = ra_prof::profile("impl_datum");
debug!("impl_datum {:?}", impl_id);
let impl_block: ImplBlock = from_chalk(db, impl_id);
let impl_: Impl = from_chalk(db, impl_id);
match impl_ {
Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
Impl::ClosureFnTraitImpl(data) => {
closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum)
}
}
}
fn impl_block_datum(
db: &impl HirDatabase,
krate: Crate,
impl_id: ImplId,
impl_block: ImplBlock,
) -> Arc<ImplDatum> {
let generic_params = impl_block.generic_params(db);
let bound_vars = Substs::bound_vars(&generic_params);
let trait_ref = impl_block
@ -657,6 +692,87 @@ pub(crate) fn impl_datum_query(
Arc::new(impl_datum)
}
fn invalid_impl_datum() -> Arc<ImplDatum> {
let trait_ref = chalk_ir::TraitRef {
trait_id: UNKNOWN_TRAIT,
parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
};
let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref),
where_clauses: Vec::new(),
associated_ty_values: Vec::new(),
impl_type: chalk_rust_ir::ImplType::External,
};
let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, 1) };
Arc::new(impl_datum)
}
fn closure_fn_trait_impl_datum(
db: &impl HirDatabase,
krate: Crate,
impl_id: ImplId,
data: super::ClosureFnTraitImplData,
) -> Option<Arc<ImplDatum>> {
// for some closure |X, Y| -> Z:
// impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
let num_args: u16 = match &db.body_hir(data.def)[data.expr] {
crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
_ => {
log::warn!("closure for closure type {:?} not found", data);
0
}
};
let arg_ty = Ty::apply(
TypeCtor::Tuple { cardinality: num_args },
(0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
);
let output_ty = Ty::Bound(num_args.into());
let sig_ty = Ty::apply(
TypeCtor::FnPtr { num_args },
(0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
);
let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() };
let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?;
let output_ty_value = chalk_rust_ir::AssociatedTyValue {
associated_ty_id: output_ty_id.to_chalk(db),
impl_id,
value: make_binders(
chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) },
0,
),
};
let impl_type = chalk_rust_ir::ImplType::External;
let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(db)),
where_clauses: Vec::new(),
associated_ty_values: vec![output_ty_value],
impl_type,
};
let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, num_args as usize + 1) };
Some(Arc::new(impl_datum))
}
fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
let lang_items = db.lang_items(krate);
let target = lang_items.target(fn_trait.lang_item_name())?;
match target {
crate::lang_item::LangItemTarget::Trait(t) => Some(*t),
_ => None,
}
}
fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
T::from_intern_id(InternId::from(chalk_id.index))
}