aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-05-22 18:31:39 +0100
committerGitHub <[email protected]>2020-05-22 18:31:39 +0100
commitb38f9a5810f28563c45acb1ae8b82438649227c9 (patch)
treeea6b68dcbd47a92a5615c74723ae69dafd7d47f9 /crates/ra_hir_ty
parentc5a22715809fa79b2c77d461c2161dbf5ebb411a (diff)
parente0f978018aad1a48390189ce54372913f324b2e3 (diff)
Merge #4570
4570: Use Chalk's built-in impls r=matklad a=flodiebold This contains two changes: - Chalk has begun adding built-in representations of primitive types; use these in our type conversion logic. There's one somewhat 'iffy' part here, namely references; we don't keep track of lifetimes, but Chalk does, so it will expect a lifetime parameter on references. If we didn't provide that, it could cause crashes in Chalk code that expects the lifetime, so I rather hackily add an (always the same) lifetime placeholder during conversion. I expect that we'll fully switch to using Chalk's types everywhere before we add lifetime support, so I think this is the best solution for now. - let Chalk know about well-known traits (from lang items), so it can apply its built-in impls. Before: ``` Total expressions: 181485 Expressions of unknown type: 2940 (1%) Expressions of partially unknown type: 2884 (1%) Type mismatches: 901 Inference: 37.821210245s, 0b allocated 0b resident Total: 53.399467609s, 0b allocated 0b resident ``` After: ``` Total expressions: 181485 Expressions of unknown type: 2923 (1%) Expressions of partially unknown type: 2879 (1%) Type mismatches: 734 Inference: 39.157752509s, 0b allocated 0b resident Total: 54.110767621s, 0b allocated 0b resident ``` (I will start splitting up `chalk.rs` in a separate PR, since it's getting pretty big...) Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs78
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs205
2 files changed, 269 insertions, 14 deletions
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 34f4b9039..6826610cb 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -2602,3 +2602,81 @@ fn test(x: &dyn Foo) {
2602 "### 2602 "###
2603 ); 2603 );
2604} 2604}
2605
2606#[test]
2607fn builtin_copy() {
2608 assert_snapshot!(
2609 infer_with_mismatches(r#"
2610#[lang = "copy"]
2611trait Copy {}
2612
2613struct IsCopy;
2614impl Copy for IsCopy {}
2615struct NotCopy;
2616
2617trait Test { fn test(&self) -> bool; }
2618impl<T: Copy> Test for T {}
2619
2620fn test() {
2621 IsCopy.test();
2622 NotCopy.test();
2623 (IsCopy, IsCopy).test();
2624 (IsCopy, NotCopy).test();
2625}
2626"#, true),
2627 @r###"
2628 111..115 'self': &Self
2629 167..268 '{ ...t(); }': ()
2630 173..179 'IsCopy': IsCopy
2631 173..186 'IsCopy.test()': bool
2632 192..199 'NotCopy': NotCopy
2633 192..206 'NotCopy.test()': {unknown}
2634 212..228 '(IsCop...sCopy)': (IsCopy, IsCopy)
2635 212..235 '(IsCop...test()': bool
2636 213..219 'IsCopy': IsCopy
2637 221..227 'IsCopy': IsCopy
2638 241..258 '(IsCop...tCopy)': (IsCopy, NotCopy)
2639 241..265 '(IsCop...test()': {unknown}
2640 242..248 'IsCopy': IsCopy
2641 250..257 'NotCopy': NotCopy
2642 "###
2643 );
2644}
2645
2646#[test]
2647fn builtin_sized() {
2648 assert_snapshot!(
2649 infer_with_mismatches(r#"
2650#[lang = "sized"]
2651trait Sized {}
2652
2653trait Test { fn test(&self) -> bool; }
2654impl<T: Sized> Test for T {}
2655
2656fn test() {
2657 1u8.test();
2658 (*"foo").test(); // not Sized
2659 (1u8, 1u8).test();
2660 (1u8, *"foo").test(); // not Sized
2661}
2662"#, true),
2663 @r###"
2664 57..61 'self': &Self
2665 114..229 '{ ...ized }': ()
2666 120..123 '1u8': u8
2667 120..130 '1u8.test()': bool
2668 136..151 '(*"foo").test()': {unknown}
2669 137..143 '*"foo"': str
2670 138..143 '"foo"': &str
2671 170..180 '(1u8, 1u8)': (u8, u8)
2672 170..187 '(1u8, ...test()': bool
2673 171..174 '1u8': u8
2674 176..179 '1u8': u8
2675 193..206 '(1u8, *"foo")': (u8, str)
2676 193..213 '(1u8, ...test()': {unknown}
2677 194..197 '1u8': u8
2678 199..205 '*"foo"': str
2679 200..205 '"foo"': &str
2680 "###
2681 );
2682}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index c2d7abd17..7d3ad6eb4 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -5,10 +5,14 @@ use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{
7 cast::Cast, fold::shift::Shift, interner::HasInterner, GenericArg, Goal, GoalData, 7 cast::Cast, fold::shift::Shift, interner::HasInterner, GenericArg, Goal, GoalData,
8 PlaceholderIndex, TypeName, UniverseIndex, 8 PlaceholderIndex, Scalar, TypeName, UniverseIndex,
9}; 9};
10 10
11use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; 11use hir_def::{
12 lang_item::{lang_attr, LangItemTarget},
13 type_ref::Mutability,
14 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId,
15};
12use ra_db::{ 16use ra_db::{
13 salsa::{InternId, InternKey}, 17 salsa::{InternId, InternKey},
14 CrateId, 18 CrateId,
@@ -16,9 +20,14 @@ use ra_db::{
16 20
17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 21use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
18use crate::{ 22use crate::{
19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, 23 db::HirDatabase,
24 display::HirDisplay,
25 method_resolution::TyFingerprint,
26 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
27 utils::generics,
20 ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 28 ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
21}; 29};
30use chalk_rust_ir::WellKnownTrait;
22 31
23pub(super) mod tls; 32pub(super) mod tls;
24 33
@@ -330,6 +339,9 @@ impl ToChalk for Ty {
330 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { 339 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
331 match self { 340 match self {
332 Ty::Apply(apply_ty) => { 341 Ty::Apply(apply_ty) => {
342 if let TypeCtor::Ref(m) = apply_ty.ctor {
343 return ref_to_chalk(db, m, apply_ty.parameters);
344 }
333 let name = apply_ty.ctor.to_chalk(db); 345 let name = apply_ty.ctor.to_chalk(db);
334 let substitution = apply_ty.parameters.to_chalk(db); 346 let substitution = apply_ty.parameters.to_chalk(db);
335 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) 347 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
@@ -373,6 +385,7 @@ impl ToChalk for Ty {
373 match chalk.data(&Interner).clone() { 385 match chalk.data(&Interner).clone() {
374 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { 386 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
375 TypeName::Error => Ty::Unknown, 387 TypeName::Error => Ty::Unknown,
388 TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution),
376 _ => { 389 _ => {
377 let ctor = from_chalk(db, apply_ty.name); 390 let ctor = from_chalk(db, apply_ty.name);
378 let parameters = from_chalk(db, apply_ty.substitution); 391 let parameters = from_chalk(db, apply_ty.substitution);
@@ -409,6 +422,41 @@ impl ToChalk for Ty {
409 } 422 }
410} 423}
411 424
425const LIFETIME_PLACEHOLDER: PlaceholderIndex =
426 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX };
427
428/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
429/// fake lifetime here, because Chalks built-in logic may expect it to be there.
430fn ref_to_chalk(
431 db: &dyn HirDatabase,
432 mutability: Mutability,
433 subst: Substs,
434) -> chalk_ir::Ty<Interner> {
435 let arg = subst[0].clone().to_chalk(db);
436 let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner);
437 chalk_ir::ApplicationTy {
438 name: TypeName::Ref(mutability.to_chalk(db)),
439 substitution: chalk_ir::Substitution::from(
440 &Interner,
441 vec![lifetime.cast(&Interner), arg.cast(&Interner)],
442 ),
443 }
444 .intern(&Interner)
445}
446
447/// Here we remove the lifetime from the type we got from Chalk.
448fn ref_from_chalk(
449 db: &dyn HirDatabase,
450 mutability: chalk_ir::Mutability,
451 subst: chalk_ir::Substitution<Interner>,
452) -> Ty {
453 let tys = subst
454 .iter(&Interner)
455 .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone())))
456 .collect();
457 Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys))
458}
459
412impl ToChalk for Substs { 460impl ToChalk for Substs {
413 type Chalk = chalk_ir::Substitution<Interner>; 461 type Chalk = chalk_ir::Substitution<Interner>;
414 462
@@ -465,7 +513,31 @@ impl ToChalk for TypeCtor {
465 let type_id = type_alias.to_chalk(db); 513 let type_id = type_alias.to_chalk(db);
466 TypeName::AssociatedType(type_id) 514 TypeName::AssociatedType(type_id)
467 } 515 }
468 _ => { 516
517 TypeCtor::Bool => TypeName::Scalar(Scalar::Bool),
518 TypeCtor::Char => TypeName::Scalar(Scalar::Char),
519 TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)),
520 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => {
521 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32))
522 }
523 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => {
524 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64))
525 }
526
527 TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()),
528 TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)),
529 TypeCtor::Slice => TypeName::Slice,
530 TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
531 TypeCtor::Str => TypeName::Str,
532
533 TypeCtor::Int(Uncertain::Unknown)
534 | TypeCtor::Float(Uncertain::Unknown)
535 | TypeCtor::Adt(_)
536 | TypeCtor::Array
537 | TypeCtor::FnDef(_)
538 | TypeCtor::FnPtr { .. }
539 | TypeCtor::Never
540 | TypeCtor::Closure { .. } => {
469 // other TypeCtors get interned and turned into a chalk StructId 541 // other TypeCtors get interned and turned into a chalk StructId
470 let struct_id = db.intern_type_ctor(self).into(); 542 let struct_id = db.intern_type_ctor(self).into();
471 TypeName::Adt(struct_id) 543 TypeName::Adt(struct_id)
@@ -479,12 +551,27 @@ impl ToChalk for TypeCtor {
479 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), 551 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
480 TypeName::OpaqueType(_) => unreachable!(), 552 TypeName::OpaqueType(_) => unreachable!(),
481 553
482 TypeName::Scalar(_) => unreachable!(), 554 TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool,
483 TypeName::Tuple(_) => unreachable!(), 555 TypeName::Scalar(Scalar::Char) => TypeCtor::Char,
484 TypeName::Raw(_) => unreachable!(), 556 TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy {
485 TypeName::Slice => unreachable!(), 557 signedness: Signedness::Signed,
486 TypeName::Ref(_) => unreachable!(), 558 bitness: bitness_from_chalk_int(int_ty),
487 TypeName::Str => unreachable!(), 559 })),
560 TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy {
561 signedness: Signedness::Unsigned,
562 bitness: bitness_from_chalk_uint(uint_ty),
563 })),
564 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => {
565 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 }))
566 }
567 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => {
568 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 }))
569 }
570 TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 },
571 TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)),
572 TypeName::Slice => TypeCtor::Slice,
573 TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)),
574 TypeName::Str => TypeCtor::Str,
488 575
489 TypeName::FnDef(_) => unreachable!(), 576 TypeName::FnDef(_) => unreachable!(),
490 577
@@ -496,6 +583,71 @@ impl ToChalk for TypeCtor {
496 } 583 }
497} 584}
498 585
586fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness {
587 use chalk_ir::UintTy;
588
589 match uint_ty {
590 UintTy::Usize => IntBitness::Xsize,
591 UintTy::U8 => IntBitness::X8,
592 UintTy::U16 => IntBitness::X16,
593 UintTy::U32 => IntBitness::X32,
594 UintTy::U64 => IntBitness::X64,
595 UintTy::U128 => IntBitness::X128,
596 }
597}
598
599fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness {
600 use chalk_ir::IntTy;
601
602 match int_ty {
603 IntTy::Isize => IntBitness::Xsize,
604 IntTy::I8 => IntBitness::X8,
605 IntTy::I16 => IntBitness::X16,
606 IntTy::I32 => IntBitness::X32,
607 IntTy::I64 => IntBitness::X64,
608 IntTy::I128 => IntBitness::X128,
609 }
610}
611
612fn int_ty_to_chalk(int_ty: IntTy) -> Scalar {
613 use chalk_ir::{IntTy, UintTy};
614
615 match int_ty.signedness {
616 Signedness::Signed => Scalar::Int(match int_ty.bitness {
617 IntBitness::Xsize => IntTy::Isize,
618 IntBitness::X8 => IntTy::I8,
619 IntBitness::X16 => IntTy::I16,
620 IntBitness::X32 => IntTy::I32,
621 IntBitness::X64 => IntTy::I64,
622 IntBitness::X128 => IntTy::I128,
623 }),
624 Signedness::Unsigned => Scalar::Uint(match int_ty.bitness {
625 IntBitness::Xsize => UintTy::Usize,
626 IntBitness::X8 => UintTy::U8,
627 IntBitness::X16 => UintTy::U16,
628 IntBitness::X32 => UintTy::U32,
629 IntBitness::X64 => UintTy::U64,
630 IntBitness::X128 => UintTy::U128,
631 }),
632 }
633}
634
635impl ToChalk for Mutability {
636 type Chalk = chalk_ir::Mutability;
637 fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
638 match self {
639 Mutability::Shared => chalk_ir::Mutability::Not,
640 Mutability::Mut => chalk_ir::Mutability::Mut,
641 }
642 }
643 fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
644 match chalk {
645 chalk_ir::Mutability::Mut => Mutability::Mut,
646 chalk_ir::Mutability::Not => Mutability::Shared,
647 }
648 }
649}
650
499impl ToChalk for Impl { 651impl ToChalk for Impl {
500 type Chalk = ImplId; 652 type Chalk = ImplId;
501 653
@@ -907,10 +1059,15 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
907 } 1059 }
908 fn well_known_trait_id( 1060 fn well_known_trait_id(
909 &self, 1061 &self,
910 _well_known_trait: chalk_rust_ir::WellKnownTrait, 1062 well_known_trait: chalk_rust_ir::WellKnownTrait,
911 ) -> Option<chalk_ir::TraitId<Interner>> { 1063 ) -> Option<chalk_ir::TraitId<Interner>> {
912 // FIXME tell Chalk about well-known traits (here and in trait_datum) 1064 let lang_attr = lang_attr_from_well_known_trait(well_known_trait);
913 None 1065 let lang_items = self.db.crate_lang_items(self.krate);
1066 let trait_ = match lang_items.target(lang_attr) {
1067 Some(LangItemTarget::TraitId(trait_)) => trait_,
1068 _ => return None,
1069 };
1070 Some(trait_.to_chalk(self.db))
914 } 1071 }
915 1072
916 fn program_clauses_for_env( 1073 fn program_clauses_for_env(
@@ -1012,7 +1169,8 @@ pub(crate) fn trait_datum_query(
1012 let associated_ty_ids = 1169 let associated_ty_ids =
1013 trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); 1170 trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect();
1014 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; 1171 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses };
1015 let well_known = None; // FIXME set this (depending on lang items) 1172 let well_known =
1173 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
1016 let trait_datum = TraitDatum { 1174 let trait_datum = TraitDatum {
1017 id: trait_id, 1175 id: trait_id,
1018 binders: make_binders(trait_datum_bound, bound_vars.len()), 1176 binders: make_binders(trait_datum_bound, bound_vars.len()),
@@ -1023,6 +1181,25 @@ pub(crate) fn trait_datum_query(
1023 Arc::new(trait_datum) 1181 Arc::new(trait_datum)
1024} 1182}
1025 1183
1184fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
1185 Some(match name {
1186 "sized" => WellKnownTrait::SizedTrait,
1187 "copy" => WellKnownTrait::CopyTrait,
1188 "clone" => WellKnownTrait::CloneTrait,
1189 "drop" => WellKnownTrait::DropTrait,
1190 _ => return None,
1191 })
1192}
1193
1194fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
1195 match attr {
1196 WellKnownTrait::SizedTrait => "sized",
1197 WellKnownTrait::CopyTrait => "copy",
1198 WellKnownTrait::CloneTrait => "clone",
1199 WellKnownTrait::DropTrait => "drop",
1200 }
1201}
1202
1026pub(crate) fn struct_datum_query( 1203pub(crate) fn struct_datum_query(
1027 db: &dyn HirDatabase, 1204 db: &dyn HirDatabase,
1028 krate: CrateId, 1205 krate: CrateId,