Repository: rust-analyzer/rust-analyzer
Pull request #8394 (2021-04-07 09:35:26)

Infer variants through type aliased enums
bors r+


Patch:
diff --git a/PRIVACY.md b/PRIVACY.md
index 27e39ca607..dd165c0e2c 100644
--- a/PRIVACY.md
+++ b/PRIVACY.md
@@ -14,4 +14,4 @@ Any other editor plugins that integrate with `rust-analyzer` are not under the c
 
 ## Others
 
-If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (on by default).
+If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (off by default).
diff --git a/README.md b/README.md
index 5fbc039644..085c8c0f63 100644
--- a/README.md
+++ b/README.md
@@ -33,9 +33,9 @@ For usage and troubleshooting requests, please use "IDEs and Editors" category o
 
 https://users.rust-lang.org/c/ide/14
 
-For questions about development and implementation, join rust-analyzer working group on Zulip:
+For questions about development and implementation, join rls-2.0 working group on Zulip:
 
-https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
+https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
 
 ## Quick Links
 
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 04e2be3906..8d46413557 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -1,4 +1,62 @@
-//! A set of high-level utility fixture methods to use in tests.
+//! Fixtures are strings containing rust source code with optional metadata.
+//! A fixture without metadata is parsed into a single source file.
+//! Use this to test functionality local to one file.
+//!
+//! Simple Example:
+//! ```
+//! r#"
+//! fn main() {
+//!     println!("Hello World")
+//! }
+//! "#
+//! ```
+//!
+//! Metadata can be added to a fixture after a `//-` comment.
+//! The basic form is specifying filenames,
+//! which is also how to define multiple files in a single test fixture
+//!
+//! Example using two files in the same crate:
+//! ```
+//! "
+//! //- /main.rs
+//! mod foo;
+//! fn main() {
+//!     foo::bar();
+//! }
+//!
+//! //- /foo.rs
+//! pub fn bar() {}
+//! "
+//! ```
+//!
+//! Example using two crates with one file each, with one crate depending on the other:
+//! ```
+//! r#"
+//! //- /main.rs crate:a deps:b
+//! fn main() {
+//!     b::foo();
+//! }
+//! //- /lib.rs crate:b
+//! pub fn b() {
+//!     println!("Hello World")
+//! }
+//! "#
+//! ```
+//!
+//! Metadata allows specifying all settings and variables
+//! that are available in a real rust project:
+//! - crate names via `crate:cratename`
+//! - dependencies via `deps:dep1,dep2`
+//! - configuration settings via `cfg:dbg=false,opt_level=2`
+//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
+//!
+//! Example using all available metadata:
+//! ```
+//! "
+//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
+//! fn insert_source_code_here() {}
+//! "
+//! ```
 use std::{mem, str::FromStr, sync::Arc};
 
 use cfg::CfgOptions;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index caa22dace3..8d00f7401b 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -58,8 +58,9 @@ use hir_ty::{
     subst_prefix,
     traits::FnTrait,
     AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
-    DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
-    TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
+    DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution,
+    SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind,
+    TyVariableKind, WhereClause,
 };
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
@@ -1821,9 +1822,8 @@ impl Type {
         );
 
         match db.trait_solve(self.krate, goal)? {
-            Solution::Unique(s) => s
+            Solution::Unique(SolutionVariables(subst)) => subst
                 .value
-                .subst
                 .interned()
                 .first()
                 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index ce6f3c0080..c013e78d94 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -185,16 +185,12 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_record_pat_field(
         &self,
-        db: &dyn HirDatabase,
+        _db: &dyn HirDatabase,
         field: &ast::RecordPatField,
     ) -> Option<Field> {
-        let field_name = field.field_name()?.as_name();
-        let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
-        let pat_id = self.pat_id(&record_pat.into())?;
-        let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
-        let variant_data = variant.variant_data(db.upcast());
-        let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
-        Some(field.into())
+        let pat_id = self.pat_id(&field.pat()?)?;
+        let struct_field = self.infer.as_ref()?.record_pat_field_resolution(pat_id)?;
+        Some(struct_field.into())
     }
 
     pub(crate) fn resolve_macro_call(
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index d9df7564d2..ab77d924a4 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -16,7 +16,7 @@ use mbe::ast_to_token_tree;
 use smallvec::{smallvec, SmallVec};
 use syntax::{
     ast::{self, AstNode, AttrsOwner},
-    match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize,
+    match_ast, AstToken, SmolStr, SyntaxNode, TextRange, TextSize,
 };
 use tt::Subtree;
 
@@ -215,11 +215,12 @@ impl Attrs {
         let mut res = ArenaMap::default();
 
         for (id, fld) in src.value.iter() {
-            let owner: &dyn AttrsOwner = match fld {
-                Either::Left(tuple) => tuple,
-                Either::Right(record) => record,
+            let attrs = match fld {
+                Either::Left(_tuple) => Attrs::default(),
+                Either::Right(record) => {
+                    RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate)
+                }
             };
-            let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate);
 
             res.insert(id, attrs);
         }
@@ -403,14 +404,10 @@ impl AttrsWithOwner {
                 return AttrSourceMap { attrs };
             }
             AttrDefId::FieldId(id) => {
-                let map = db.fields_attrs_source_map(id.parent);
-                let file_id = id.parent.file_id(db);
-                let root = db.parse_or_expand(file_id).unwrap();
-                let owner = match &map[id.local_id] {
-                    Either::Left(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
-                    Either::Right(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
-                };
-                InFile::new(file_id, owner)
+                id.parent.child_source(db).map(|source| match &source[id.local_id] {
+                    Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()),
+                    Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()),
+                })
             }
             AttrDefId::AdtId(adt) => match adt {
                 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -418,12 +415,10 @@ impl AttrsWithOwner {
                 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
             },
             AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
-            AttrDefId::EnumVariantId(id) => {
-                let map = db.variants_attrs_source_map(id.parent);
-                let file_id = id.parent.lookup(db).id.file_id();
-                let root = db.parse_or_expand(file_id).unwrap();
-                InFile::new(file_id, ast::AttrsOwnerNode::new(map[id.local_id].to_node(&root)))
-            }
+            AttrDefId::EnumVariantId(id) => id
+                .parent
+                .child_source(db)
+                .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
             AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
             AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
             AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -752,36 +747,3 @@ fn collect_attrs(
 
     attrs.into_iter().map(|(_, attr)| attr)
 }
-
-pub(crate) fn variants_attrs_source_map(
-    db: &dyn DefDatabase,
-    def: EnumId,
-) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>> {
-    let mut res = ArenaMap::default();
-    let child_source = def.child_source(db);
-
-    for (idx, variant) in child_source.value.iter() {
-        res.insert(idx, AstPtr::new(variant));
-    }
-
-    Arc::new(res)
-}
-
-pub(crate) fn fields_attrs_source_map(
-    db: &dyn DefDatabase,
-    def: VariantId,
-) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>> {
-    let mut res = ArenaMap::default();
-    let child_source = def.child_source(db);
-
-    for (idx, variant) in child_source.value.iter() {
-        res.insert(
-            idx,
-            variant
-                .as_ref()
-                .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))),
-        );
-    }
-
-    Arc::new(res)
-}
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 7eadc8e0d6..9b7a213a12 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -2,10 +2,9 @@
 use std::sync::Arc;
 
 use base_db::{salsa, CrateId, SourceDatabase, Upcast};
-use either::Either;
 use hir_expand::{db::AstDatabase, HirFileId};
 use la_arena::ArenaMap;
-use syntax::{ast, AstPtr, SmolStr};
+use syntax::SmolStr;
 
 use crate::{
     adt::{EnumData, StructData},
@@ -123,18 +122,6 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
     #[salsa::invoke(Attrs::fields_attrs_query)]
     fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
 
-    #[salsa::invoke(crate::attr::variants_attrs_source_map)]
-    fn variants_attrs_source_map(
-        &self,
-        def: EnumId,
-    ) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>>;
-
-    #[salsa::invoke(crate::attr::fields_attrs_source_map)]
-    fn fields_attrs_source_map(
-        &self,
-        def: VariantId,
-    ) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>>;
-
     #[salsa::invoke(AttrsWithOwner::attrs_query)]
     fn attrs(&self, def: AttrDefId) -> AttrsWithOwner;
 
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 9014468ea0..a8ee5eeac9 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::format_to;
 
 use crate::{
-    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
+    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId,
     LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
 };
 
@@ -37,7 +37,6 @@ pub struct ItemScope {
 
     defs: Vec<ModuleDefId>,
     impls: Vec<ImplId>,
-    unnamed_consts: Vec<ConstId>,
     /// Traits imported via `use Trait as _;`.
     unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
     /// Macros visible in current module in legacy textual scope
@@ -107,10 +106,6 @@ impl ItemScope {
             .map(|(_, v)| v)
     }
 
-    pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
-        self.unnamed_consts.iter().copied()
-    }
-
     /// Iterate over all module scoped macros
     pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
         self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
@@ -161,10 +156,6 @@ impl ItemScope {
         self.impls.push(imp)
     }
 
-    pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
-        self.unnamed_consts.push(konst);
-    }
-
     pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
         self.legacy_macros.insert(name, mac);
     }
@@ -304,7 +295,6 @@ impl ItemScope {
             unresolved,
             defs,
             impls,
-            unnamed_consts,
             unnamed_trait_imports,
             legacy_macros,
         } = self;
@@ -314,7 +304,6 @@ impl ItemScope {
         unresolved.shrink_to_fit();
         defs.shrink_to_fit();
         impls.shrink_to_fit();
-        unnamed_consts.shrink_to_fit();
         unnamed_trait_imports.shrink_to_fit();
         legacy_macros.shrink_to_fit();
     }
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index e2af0e5148..abd6c553fe 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -453,14 +453,6 @@ impl VariantId {
             }
         }
     }
-
-    pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
-        match self {
-            VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
-            VariantId::StructId(it) => it.lookup(db).id.file_id(),
-            VariantId::UnionId(it) => it.lookup(db).id.file_id(),
-        }
-    }
 }
 
 trait Intern {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 492d8c71ff..f42f927023 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1163,27 +1163,19 @@ impl ModCollector<'_, '_> {
                 }
                 ModItem::Const(id) => {
                     let it = &self.item_tree[id];
-                    let const_id = ConstLoc {
-                        container: module.into(),
-                        id: ItemTreeId::new(self.file_id, id),
-                    }
-                    .intern(self.def_collector.db);
-
-                    match &it.name {
-                        Some(name) => {
-                            def = Some(DefData {
-                                id: const_id.into(),
-                                name,
-                                visibility: &self.item_tree[it.visibility],
-                                has_constructor: false,
-                            });
-                        }
-                        None => {
-                            // const _: T = ...;
-                            self.def_collector.def_map.modules[self.module_id]
-                                .scope
-                                .define_unnamed_const(const_id);
-                        }
+
+                    if let Some(name) = &it.name {
+                        def = Some(DefData {
+                            id: ConstLoc {
+                                container: module.into(),
+                                id: ItemTreeId::new(self.file_id, id),
+                            }
+                            .intern(self.def_collector.db)
+                            .into(),
+                            name,
+                            visibility: &self.item_tree[it.visibility],
+                            has_constructor: false,
+                        });
                     }
                 }
                 ModItem::Static(id) => {
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 80e192a575..c5890e24df 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -120,8 +120,8 @@ fn deref_by_trait(
             // assumptions will be broken. We would need to properly introduce
             // new variables in that case
 
-            for i in 1..vars.binders.len(&Interner) {
-                if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
+            for i in 1..vars.0.binders.len(&Interner) {
+                if vars.0.value.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
                     != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
                 {
                     warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
@@ -130,12 +130,12 @@ fn deref_by_trait(
             }
             Some(Canonical {
                 value: vars
+                    .0
                     .value
-                    .subst
-                    .at(&Interner, vars.value.subst.len(&Interner) - 1)
+                    .at(&Interner, vars.0.value.len(&Interner) - 1)
                     .assert_ty_ref(&Interner)
                     .clone(),
-                binders: vars.binders.clone(),
+                binders: vars.0.binders.clone(),
             })
         }
         Solution::Ambig(_) => {
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 7c6c3600b8..796f77ab0d 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -42,7 +42,7 @@ use super::{
 };
 use crate::{
     db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
-    to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, TyBuilder, TyExt, TyKind,
+    to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyExt, TyKind,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -131,7 +131,8 @@ pub struct InferenceResult {
     method_resolutions: FxHashMap<ExprId, FunctionId>,
     /// For each field access expr, records the field it resolves to.
     field_resolutions: FxHashMap<ExprId, FieldId>,
-    /// For each struct literal or pattern, records the variant it resolves to.
+    record_pat_field_resolutions: FxHashMap<PatId, FieldId>,
+    /// For each struct literal, records the variant it resolves to.
     variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
     /// For each associated item record what it resolves to
     assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
@@ -150,6 +151,9 @@ impl InferenceResult {
     pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
         self.field_resolutions.get(&expr).copied()
     }
+    pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> {
+        self.record_pat_field_resolutions.get(&pat).copied()
+    }
     pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
         self.variant_resolutions.get(&id.into()).copied()
     }
@@ -342,18 +346,11 @@ impl<'a> InferenceContext<'a> {
                 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
 
             match solution {
-                Some(Solution::Unique(canonical_subst)) => {
-                    canonicalized.apply_solution(
-                        self,
-                        Canonical {
-                            binders: canonical_subst.binders,
-                            // FIXME: handle constraints
-                            value: canonical_subst.value.subst,
-                        },
-                    );
+                Some(Solution::Unique(substs)) => {
+                    canonicalized.apply_solution(self, substs.0);
                 }
                 Some(Solution::Ambig(Guidance::Definite(substs))) => {
-                    canonicalized.apply_solution(self, substs);
+                    canonicalized.apply_solution(self, substs.0);
                     self.obligations.push(obligation);
                 }
                 Some(_) => {
@@ -487,36 +484,13 @@ impl<'a> InferenceContext<'a> {
                 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
                 let substs = generics.type_params_subst(self.db);
                 let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs);
-                match unresolved {
-                    None => {
-                        let variant = ty_variant(&ty);
-                        (ty, variant)
-                    }
-                    Some(1) => {
-                        let segment = path.mod_path().segments().last().unwrap();
-                        // this could be an enum variant or associated type
-                        if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
-                            let enum_data = self.db.enum_data(enum_id);
-                            if let Some(local_id) = enum_data.variant(segment) {
-                                let variant = EnumVariantId { parent: enum_id, local_id };
-                                return (ty, Some(variant.into()));
-                            }
-                        }
-                        // FIXME potentially resolve assoc type
-                        (self.err_ty(), None)
-                    }
-                    Some(_) => {
-                        // FIXME diagnostic
-                        (self.err_ty(), None)
-                    }
-                }
+                self.resolve_variant_on_alias(ty, unresolved, path)
             }
             TypeNs::TypeAliasId(it) => {
                 let ty = TyBuilder::def_ty(self.db, it.into())
                     .fill(std::iter::repeat_with(|| self.table.new_type_var()))
                     .build();
-                let variant = ty_variant(&ty);
-                forbid_unresolved_segments((ty, variant), unresolved)
+                self.resolve_variant_on_alias(ty, unresolved, path)
             }
             TypeNs::AdtSelfType(_) => {
                 // FIXME this could happen in array size expressions, once we're checking them
@@ -543,16 +517,43 @@ impl<'a> InferenceContext<'a> {
                 (TyKind::Error.intern(&Interner), None)
             }
         }
+    }
 
-        fn ty_variant(ty: &Ty) -> Option<VariantId> {
-            ty.as_adt().and_then(|(adt_id, _)| match adt_id {
-                AdtId::StructId(s) => Some(VariantId::StructId(s)),
-                AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
-                AdtId::EnumId(_) => {
-                    // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
-                    None
+    fn resolve_variant_on_alias(
+        &mut self,
+        ty: Ty,
+        unresolved: Option<usize>,
+        path: &Path,
+    ) -> (Ty, Option<VariantId>) {
+        match unresolved {
+            None => {
+                let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
+                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
+                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
+                    AdtId::EnumId(_) => {
+                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
+                        None
+                    }
+                });
+                (ty, variant)
+            }
+            Some(1) => {
+                let segment = path.mod_path().segments().last().unwrap();
+                // this could be an enum variant or associated type
+                if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
+                    let enum_data = self.db.enum_data(enum_id);
+                    if let Some(local_id) = enum_data.variant(segment) {
+                        let variant = EnumVariantId { parent: enum_id, local_id };
+                        return (ty, Some(variant.into()));
+                    }
                 }
-            })
+                // FIXME potentially resolve assoc type
+                (self.err_ty(), None)
+            }
+            Some(_) => {
+                // FIXME diagnostic
+                (self.err_ty(), None)
+            }
         }
     }
 
@@ -690,6 +691,25 @@ impl<'a> InferenceContext<'a> {
     }
 }
 
+/// The kinds of placeholders we need during type inference. There's separate
+/// values for general types, and for integer and float variables. The latter
+/// two are used for inference of literal values (e.g. `100` could be one of
+/// several integer types).
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct InferenceVar {
+    index: u32,
+}
+
+impl InferenceVar {
+    fn to_inner(self) -> unify::TypeVarId {
+        unify::TypeVarId(self.index)
+    }
+
+    fn from_inner(unify::TypeVarId(index): unify::TypeVarId) -> Self {
+        InferenceVar { index }
+    }
+}
+
 /// When inferring an expression, we propagate downward whatever type hint we
 /// are able in the form of an `Expectation`.
 #[derive(Clone, PartialEq, Eq, Debug)]
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index f1af2a0bdc..159a53a631 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -7,7 +7,7 @@
 use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
 use hir_def::lang_item::LangItemTarget;
 
-use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
+use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
 
 use super::{InEnvironment, InferenceContext};
 
@@ -148,14 +148,7 @@ impl<'a> InferenceContext<'a> {
 
         match solution {
             Solution::Unique(v) => {
-                canonicalized.apply_solution(
-                    self,
-                    Canonical {
-                        binders: v.binders,
-                        // FIXME handle constraints
-                        value: v.value.subst,
-                    },
-                );
+                canonicalized.apply_solution(self, v.0);
             }
             _ => return None,
         };
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index e4813c87c1..942f70edf5 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -7,6 +7,7 @@ use chalk_ir::Mutability;
 use hir_def::{
     expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
     path::Path,
+    FieldId,
 };
 use hir_expand::name::Name;
 
@@ -79,6 +80,11 @@ impl<'a> InferenceContext<'a> {
         let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
         for subpat in subpats {
             let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
+            if let Some(local_id) = matching_field {
+                let field_def = FieldId { parent: def.unwrap(), local_id };
+                self.result.record_pat_field_resolutions.insert(subpat.pat, field_def);
+            }
+
             let expected_ty = matching_field.map_or(self.err_ty(), |field| {
                 field_tys[field].clone().substitute(&Interner, &substs)
             });
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index d717e33759..7d76cda684 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -51,7 +51,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
         t.fold_binders(
             &mut |ty, binders| match ty.kind(&Interner) {
                 &TyKind::InferenceVar(var, kind) => {
-                    let inner = from_inference_var(var);
+                    let inner = var.to_inner();
                     if self.var_stack.contains(&inner) {
                         // recursive type
                         return self.ctx.table.type_variable_table.fallback_value(var, kind);
@@ -65,7 +65,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
                         result
                     } else {
                         let root = self.ctx.table.var_unification_table.find(inner);
-                        let position = self.add(to_inference_var(root), kind);
+                        let position = self.add(InferenceVar::from_inner(root), kind);
                         TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner)
                     }
                 }
@@ -207,16 +207,16 @@ impl TypeVariableTable {
     }
 
     pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
-        self.inner[from_inference_var(iv).0 as usize].diverging = diverging;
+        self.inner[iv.to_inner().0 as usize].diverging = diverging;
     }
 
     fn is_diverging(&mut self, iv: InferenceVar) -> bool {
-        self.inner[from_inference_var(iv).0 as usize].diverging
+        self.inner[iv.to_inner().0 as usize].diverging
     }
 
     fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
         match kind {
-            _ if self.inner[from_inference_var(iv).0 as usize].diverging => TyKind::Never,
+            _ if self.inner[iv.to_inner().0 as usize].diverging => TyKind::Never,
             TyVariableKind::General => TyKind::Error,
             TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
             TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
@@ -250,7 +250,7 @@ impl InferenceTable {
         self.type_variable_table.push(TypeVariableData { diverging });
         let key = self.var_unification_table.new_key(TypeVarValue::Unknown);
         assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1);
-        TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner)
+        TyKind::InferenceVar(InferenceVar::from_inner(key), kind).intern(&Interner)
     }
 
     pub(crate) fn new_type_var(&mut self) -> Ty {
@@ -369,12 +369,8 @@ impl InferenceTable {
                 == self.type_variable_table.is_diverging(*tv2) =>
             {
                 // both type vars are unknown since we tried to resolve them
-                if !self
-                    .var_unification_table
-                    .unioned(from_inference_var(*tv1), from_inference_var(*tv2))
-                {
-                    self.var_unification_table
-                        .union(from_inference_var(*tv1), from_inference_var(*tv2));
+                if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) {
+                    self.var_unification_table.union(tv1.to_inner(), tv2.to_inner());
                     self.revision += 1;
                 }
                 true
@@ -411,7 +407,7 @@ impl InferenceTable {
             ) => {
                 // the type var is unknown since we tried to resolve it
                 self.var_unification_table.union_value(
-                    from_inference_var(*tv),
+                    tv.to_inner(),
                     TypeVarValue::Known(other.clone().intern(&Interner)),
                 );
                 self.revision += 1;
@@ -466,7 +462,7 @@ impl InferenceTable {
             }
             match ty.kind(&Interner) {
                 TyKind::InferenceVar(tv, _) => {
-                    let inner = from_inference_var(*tv);
+                    let inner = tv.to_inner();
                     match self.var_unification_table.inlined_probe_value(inner).known() {
                         Some(known_ty) => {
                             // The known_ty can't be a type var itself
@@ -489,7 +485,7 @@ impl InferenceTable {
     fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
         ty.fold(&mut |ty| match ty.kind(&Interner) {
             &TyKind::InferenceVar(tv, kind) => {
-                let inner = from_inference_var(tv);
+                let inner = tv.to_inner();
                 if tv_stack.contains(&inner) {
                     cov_mark::hit!(type_var_cycles_resolve_as_possible);
                     // recursive type
@@ -516,7 +512,7 @@ impl InferenceTable {
     fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
         ty.fold(&mut |ty| match ty.kind(&Interner) {
             &TyKind::InferenceVar(tv, kind) => {
-                let inner = from_inference_var(tv);
+                let inner = tv.to_inner();
                 if tv_stack.contains(&inner) {
                     cov_mark::hit!(type_var_cycles_resolve_completely);
                     // recursive type
@@ -559,14 +555,6 @@ impl UnifyKey for TypeVarId {
     }
 }
 
-fn from_inference_var(var: InferenceVar) -> TypeVarId {
-    TypeVarId(var.index())
-}
-
-fn to_inference_var(TypeVarId(index): TypeVarId) -> InferenceVar {
-    index.into()
-}
-
 /// The value of a type variable: either we already know the type, or we don't
 /// know it yet.
 #[derive(Clone, PartialEq, Eq, Debug)]
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 5c83a508d4..f5b658cbae 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -42,7 +42,7 @@ use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
 pub use autoderef::autoderef;
 pub use builder::TyBuilder;
 pub use chalk_ext::{ProjectionTyExt, TyExt};
-pub use infer::{could_unify, InferenceResult};
+pub use infer::{could_unify, InferenceResult, InferenceVar};
 pub use lower::{
     associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
     TyDefId, TyLoweringContext, ValueTyDefId,
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index f29319f206..ee725fd468 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,8 +8,8 @@ use arrayvec::ArrayVec;
 use base_db::CrateId;
 use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 use hir_def::{
-    lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId,
-    GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
+    lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule,
+    ImplId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -100,38 +100,25 @@ impl TraitImpls {
         let mut impls = Self { map: FxHashMap::default() };
 
         let crate_def_map = db.crate_def_map(krate);
-        collect_def_map(db, &crate_def_map, &mut impls);
-
-        return Arc::new(impls);
-
-        fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) {
-            for (_module_id, module_data) in def_map.modules() {
-                for impl_id in module_data.scope.impls() {
-                    let target_trait = match db.impl_trait(impl_id) {
-                        Some(tr) => tr.skip_binders().hir_trait_id(),
-                        None => continue,
-                    };
-                    let self_ty = db.impl_self_ty(impl_id);
-                    let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders());
-                    impls
-                        .map
-                        .entry(target_trait)
-                        .or_default()
-                        .entry(self_ty_fp)
-                        .or_default()
-                        .push(impl_id);
-                }
-
-                // To better support custom derives, collect impls in all unnamed const items.
-                // const _: () = { ... };
-                for konst in module_data.scope.unnamed_consts() {
-                    let body = db.body(konst.into());
-                    for (_, block_def_map) in body.blocks(db.upcast()) {
-                        collect_def_map(db, &block_def_map, impls);
-                    }
-                }
+        for (_module_id, module_data) in crate_def_map.modules() {
+            for impl_id in module_data.scope.impls() {
+                let target_trait = match db.impl_trait(impl_id) {
+                    Some(tr) => tr.skip_binders().hir_trait_id(),
+                    None => continue,
+                };
+                let self_ty = db.impl_self_ty(impl_id);
+                let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders());
+                impls
+                    .map
+                    .entry(target_trait)
+                    .or_default()
+                    .entry(self_ty_fp)
+                    .or_default()
+                    .push(impl_id);
             }
         }
+
+        Arc::new(impls)
     }
 
     pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
@@ -221,9 +208,6 @@ impl InherentImpls {
             }
         }
 
-        // NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only
-        // support trait impls there.
-
         Arc::new(Self { map })
     }
 
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 3374532c34..c8883485c0 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -9,7 +9,7 @@ use stdx::panic_context;
 
 use crate::{
     db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
-    Solution, Ty, TyKind, WhereClause,
+    Solution, SolutionVariables, Ty, TyKind, WhereClause,
 };
 
 use self::chalk::{from_chalk, Interner, ToChalk};
@@ -173,15 +173,23 @@ fn solution_from_chalk(
     db: &dyn HirDatabase,
     solution: chalk_solve::Solution<Interner>,
 ) -> Solution {
+    let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
+        let result = from_chalk(db, subst);
+        SolutionVariables(result)
+    };
     match solution {
         chalk_solve::Solution::Unique(constr_subst) => {
-            Solution::Unique(from_chalk(db, constr_subst))
+            let subst = chalk_ir::Canonical {
+                value: constr_subst.value.subst,
+                binders: constr_subst.binders,
+            };
+            Solution::Unique(convert_subst(subst))
         }
         chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => {
-            Solution::Ambig(Guidance::Definite(from_chalk(db, subst)))
+            Solution::Ambig(Guidance::Definite(convert_subst(subst)))
         }
         chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => {
-            Solution::Ambig(Guidance::Suggested(from_chalk(db, subst)))
+            Solution::Ambig(Guidance::Suggested(convert_subst(subst)))
         }
         chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => {
             Solution::Ambig(Guidance::Unknown)
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 84abd99b29..cf73cb0784 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -10,9 +10,10 @@ use base_db::salsa::InternKey;
 use hir_def::{GenericDefId, TypeAliasId};
 
 use crate::{
-    chalk_ext::ProjectionTyExt, db::HirDatabase, static_lifetime, AliasTy, CallableDefId,
-    Canonical, ConstrainedSubst, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy,
-    ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
+    chalk_ext::ProjectionTyExt, db::HirDatabase, dummy_usize_const, static_lifetime, AliasTy,
+    CallableDefId, Canonical, Const, DomainGoal, FnPointer, GenericArg, InEnvironment, Lifetime,
+    OpaqueTy, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk,
+    WhereClause,
 };
 
 use super::interner::*;
@@ -22,16 +23,16 @@ impl ToChalk for Ty {
     type Chalk = chalk_ir::Ty<Interner>;
     fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
         match self.into_inner() {
-            TyKind::Ref(m, lt, ty) => {
-                chalk_ir::TyKind::Ref(m, lt, ty.to_chalk(db)).intern(&Interner)
-            }
-            TyKind::Array(ty, size) => {
-                chalk_ir::TyKind::Array(ty.to_chalk(db), size).intern(&Interner)
-            }
-            TyKind::Function(FnPointer { sig, substitution: substs, num_binders }) => {
+            TyKind::Ref(m, lt, ty) => ref_to_chalk(db, m, lt, ty),
+            TyKind::Array(ty, size) => array_to_chalk(db, ty, size),
+            TyKind::Function(FnPointer { sig, substitution: substs, .. }) => {
                 let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db));
-                chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders, sig, substitution })
-                    .intern(&Interner)
+                chalk_ir::TyKind::Function(chalk_ir::FnPointer {
+                    num_binders: 0,
+                    sig,
+                    substitution,
+                })
+                .intern(&Interner)
             }
             TyKind::AssociatedType(assoc_type_id, substs) => {
                 let substitution = substs.to_chalk(db);
@@ -73,12 +74,21 @@ impl ToChalk for Ty {
                 chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
             }
             TyKind::Alias(AliasTy::Projection(proj_ty)) => {
-                chalk_ir::AliasTy::Projection(proj_ty.to_chalk(db))
-                    .cast(&Interner)
-                    .intern(&Interner)
+                let associated_ty_id = proj_ty.associated_ty_id;
+                let substitution = proj_ty.substitution.to_chalk(db);
+                chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+                    associated_ty_id,
+                    substitution,
+                })
+                .cast(&Interner)
+                .intern(&Interner)
             }
             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
-                chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)).cast(&Interner).intern(&Interner)
+                let opaque_ty_id = opaque_ty.opaque_ty_id;
+                let substitution = opaque_ty.substitution.to_chalk(db);
+                chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id, substitution })
+                    .cast(&Interner)
+                    .intern(&Interner)
             }
             TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
             TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
@@ -91,7 +101,7 @@ impl ToChalk for Ty {
                 );
                 let bounded_ty = chalk_ir::DynTy {
                     bounds: chalk_ir::Binders::new(binders, where_clauses),
-                    lifetime: dyn_ty.lifetime,
+                    lifetime: static_lifetime(),
                 };
                 chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
             }
@@ -104,10 +114,17 @@ impl ToChalk for Ty {
             chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size),
             chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
             chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
-                TyKind::Alias(AliasTy::Projection(from_chalk(db, proj)))
+                let associated_ty = proj.associated_ty_id;
+                let parameters = from_chalk(db, proj.substitution);
+                TyKind::Alias(AliasTy::Projection(ProjectionTy {
+                    associated_ty_id: associated_ty,
+                    substitution: parameters,
+                }))
             }
             chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
-                TyKind::Alias(AliasTy::Opaque(from_chalk(db, opaque_ty)))
+                let opaque_ty_id = opaque_ty.opaque_ty_id;
+                let parameters = from_chalk(db, opaque_ty.substitution);
+                TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, substitution: parameters }))
             }
             chalk_ir::TyKind::Function(chalk_ir::FnPointer {
                 num_binders,
@@ -121,19 +138,18 @@ impl ToChalk for Ty {
             }
             chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
             chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error,
-            chalk_ir::TyKind::Dyn(dyn_ty) => {
-                assert_eq!(dyn_ty.bounds.binders.len(&Interner), 1);
-                let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
-                let where_clauses = crate::QuantifiedWhereClauses::from_iter(
-                    &Interner,
-                    bounds.interned().iter().cloned().map(|p| from_chalk(db, p)),
-                );
+            chalk_ir::TyKind::Dyn(where_clauses) => {
+                assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
+                let bounds = where_clauses
+                    .bounds
+                    .skip_binders()
+                    .iter(&Interner)
+                    .map(|c| from_chalk(db, c.clone()));
                 TyKind::Dyn(crate::DynTy {
-                    bounds: crate::Binders::new(binders, where_clauses),
-                    // HACK: we sometimes get lifetime variables back in solutions
-                    // from Chalk, and don't have the infrastructure to substitute
-                    // them yet. So for now we just turn them into 'static right
-                    // when we get them
+                    bounds: crate::Binders::new(
+                        where_clauses.bounds.binders.clone(),
+                        crate::QuantifiedWhereClauses::from_iter(&Interner, bounds),
+                    ),
                     lifetime: static_lifetime(),
                 })
             }
@@ -153,12 +169,8 @@ impl ToChalk for Ty {
             }
             chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
             chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
-            chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => {
-                // HACK: we sometimes get lifetime variables back in solutions
-                // from Chalk, and don't have the infrastructure to substitute
-                // them yet. So for now we just turn them into 'static right
-                // when we get them
-                TyKind::Ref(mutability, static_lifetime(), from_chalk(db, ty))
+            chalk_ir::TyKind::Ref(mutability, lifetime, ty) => {
+                TyKind::Ref(mutability, lifetime, from_chalk(db, ty))
             }
             chalk_ir::TyKind::Str => TyKind::Str,
             chalk_ir::TyKind::Never => TyKind::Never,
@@ -177,6 +189,26 @@ impl ToChalk for Ty {
     }
 }
 
+/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
+/// fake lifetime here, because Chalks built-in logic may expect it to be there.
+fn ref_to_chalk(
+    db: &dyn HirDatabase,
+    mutability: chalk_ir::Mutability,
+    _lifetime: Lifetime,
+    ty: Ty,
+) -> chalk_ir::Ty<Interner> {
+    let arg = ty.to_chalk(db);
+    let lifetime = static_lifetime();
+    chalk_ir::TyKind::Ref(mutability, lifetime, arg).intern(&Interner)
+}
+
+/// We currently don't model constants, but Chalk does. So, we have to insert a
+/// fake constant here, because Chalks built-in logic may expect it to be there.
+fn array_to_chalk(db: &dyn HirDatabase, ty: Ty, _: Const) -> chalk_ir::Ty<Interner> {
+    let arg = ty.to_chalk(db);
+    chalk_ir::TyKind::Array(arg, dummy_usize_const()).intern(&Interner)
+}
+
 impl ToChalk for GenericArg {
     type Chalk = chalk_ir::GenericArg<Interner>;
 
@@ -459,18 +491,6 @@ where
     }
 }
 
-impl ToChalk for crate::ConstrainedSubst {
-    type Chalk = chalk_ir::ConstrainedSubst<Interner>;
-
-    fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
-        unimplemented!()
-    }
-
-    fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
-        ConstrainedSubst { subst: from_chalk(db, chalk.subst) }
-    }
-}
-
 pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
 where
     T: HasInterner<Interner = Interner>,
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs
index c25bc2d6ab..89c0ddd1a4 100644
--- a/crates/hir_ty/src/types.rs
+++ b/crates/hir_ty/src/types.rs
@@ -11,7 +11,8 @@ use smallvec::SmallVec;
 
 use crate::{
     AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId,
-    Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds,
+    InferenceVar, Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind,
+    VariableKinds,
 };
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -490,16 +491,14 @@ pub struct AliasEq {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct ConstrainedSubst {
-    pub subst: Substitution,
-}
+pub struct SolutionVariables(pub Canonical<Substitution>);
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 /// A (possible) solution for a proposed goal.
 pub enum Solution {
     /// The goal indeed holds, and there is a unique value for all existential
     /// variables.
-    Unique(Canonical<ConstrainedSubst>),
+    Unique(SolutionVariables),
 
     /// The goal may be provable in multiple ways, but regardless we may have some guidance
     /// for type inference. In this case, we don't return any lifetime
@@ -515,35 +514,13 @@ pub enum Guidance {
     /// The existential variables *must* have the given values if the goal is
     /// ever to hold, but that alone isn't enough to guarantee the goal will
     /// actually hold.
-    Definite(Canonical<Substitution>),
+    Definite(SolutionVariables),
 
     /// There are multiple plausible values for the existentials, but the ones
     /// here are suggested as the preferred choice heuristically. These should
     /// be used for inference fallback only.
-    Suggested(Canonical<Substitution>),
+    Suggested(SolutionVariables),
 
     /// There's no useful information to feed back to type inference
     Unknown,
 }
-
-/// The kinds of placeholders we need during type inference. There's separate
-/// values for general types, and for integer and float variables. The latter
-/// two are used for inference of literal values (e.g. `100` could be one of
-/// several integer types).
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub struct InferenceVar {
-    index: u32,
-}
-
-impl From<u32> for InferenceVar {
-    fn from(index: u32) -> InferenceVar {
-        InferenceVar { index }
-    }
-}
-
-impl InferenceVar {
-    /// Gets the underlying index value.
-    pub fn index(self) -> u32 {
-        self.index
-    }
-}
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index d5628e3df1..9eeabbedaf 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -103,9 +103,6 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
                 format!("\n{}}}", "  ".repeat(indent))
             }
             R_CURLY => format!("}}\n{}", "  ".repeat(indent)),
-            LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
-                format!("{} ", token.text().to_string())
-            }
             T![;] => format!(";\n{}", "  ".repeat(indent)),
             T![->] => " -> ".to_string(),
             T![=] => " = ".to_string(),
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 9ace13e411..1ad0171982 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -113,7 +113,6 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     if ctx.use_item_syntax.is_some()
         || ctx.attribute_under_caret.is_some()
         || ctx.mod_declaration_under_caret.is_some()
-        || ctx.record_lit_syntax.is_some()
     {
         return None;
     }
@@ -1035,46 +1034,4 @@ fn main() {
             expect![[]],
         );
     }
-
-    #[test]
-    fn no_fuzzy_during_fields_of_record_lit_syntax() {
-        check(
-            r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-struct Foo {
-    some_field: i32,
-}
-fn main() {
-    let _ = Foo { so$0 };
-}
-"#,
-            expect![[]],
-        );
-    }
-
-    #[test]
-    fn fuzzy_after_fields_of_record_lit_syntax() {
-        check(
-            r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-struct Foo {
-    some_field: i32,
-}
-fn main() {
-    let _ = Foo { some_field: so$0 };
-}
-"#,
-            expect![[r#"
-                fn some_fn() (m::some_fn) fn() -> i32
-            "#]],
-        );
-    }
 }
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index 6c67425d75..111e9325a4 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -152,10 +152,6 @@ impl RootDatabase {
             hir::db::FileItemTreeQuery
             hir::db::BlockDefMapQuery
             hir::db::CrateDefMapQueryQuery
-            hir::db::FieldsAttrsQuery
-            hir::db::VariantsAttrsQuery
-            hir::db::FieldsAttrsSourceMapQuery
-            hir::db::VariantsAttrsSourceMapQuery
             hir::db::StructDataQuery
             hir::db::UnionDataQuery
             hir::db::EnumDataQuery
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 9c0eb13582..eab21a7653 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -24,7 +24,7 @@ Rust Analyzer is a part of [RLS-2.0 working
 group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0).
 Discussion happens in this Zulip stream:
 
-https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
+https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0
 
 # Issue Labels
 
@@ -32,8 +32,6 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
   are good issues to get into the project.
 * [E-has-instructions](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions)
   issues have links to the code in question and tests.
-* [Broken Window](https://github.com/rust-analyzer/rust-analyzer/issues?q=is:issue+is:open+label:%22Broken+Window%22)
-  are issues which are not critical by themselves, but which should be fixed ASAP regardless, to avoid accumulation of technical debt.
 * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy),
   [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium),
   [E-hard](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard),
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index 3ffd9e8cbb..fb991133aa 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c
 ## Entry Points
 
 `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP.
-This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it.
+This is *the* entry point, but it front-loads a lot of complexity, so its fine to just skim through it.
 
 `crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP.
 
@@ -67,7 +67,7 @@ They are handled by Rust code in the xtask directory.
 
 VS Code plugin.
 
-### `lib/`
+### `libs/`
 
 rust-analyzer independent libraries which we publish to crates.io.
 It's not heavily utilized at the moment.
@@ -139,8 +139,7 @@ If an AST method returns an `Option`, it *can* be `None` at runtime, even if thi
 ### `crates/base_db`
 
 We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation.
-Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. 
-The `base_db` crate provides basic infrastructure for interacting with salsa.
+Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. The `base_db` crate provides basic infrastructure for interacting with salsa.
 Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer.
 Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs.
 
@@ -222,7 +221,7 @@ Internally, `ide` is split across several crates. `ide_assists`, `ide_completion
 The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features.
 
 **Architecture Invariant:** `ide` crate strives to provide a _perfect_ API.
-Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design.
+Although at the moment it has only one consumer, the LSP server, LSP *does not* influence it's API design.
 Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies.
 
 ### `crates/rust-analyzer`
@@ -308,7 +307,7 @@ This sections talks about the things which are everywhere and nowhere in particu
 
 ### Code generation
 
-Some ]components in this repository are generated through automatic processes.
+Some of the components of this repository are generated through automatic processes.
 Generated code is updated automatically on `cargo test`.
 Generated code is generally committed to the git repository.
 
@@ -390,7 +389,7 @@ fn spam() {
 ```
 
 To specify input data, we use a single string literal in a special format, which can describe a set of rust files.
-See the `Fixture` its module for fixture examples and documentation.
+See the `Fixture` type.
 
 **Architecture Invariant:** all code invariants are tested by `#[test]` tests.
 There's no additional checks in CI, formatting and tidy tests are run with `cargo test`.
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index a46121bb2e..989771ac6f 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -51,8 +51,8 @@ interface SnippetTextEdit extends TextEdit {
 
 ```typescript
 export interface TextDocumentEdit {
-    textDocument: OptionalVersionedTextDocumentIdentifier;
-    edits: (TextEdit | SnippetTextEdit)[];
+	textDocument: OptionalVersionedTextDocumentIdentifier;
+	edits: (TextEdit | SnippetTextEdit)[];
 }
 ```
 
@@ -145,9 +145,9 @@ mod foo;
 ### Unresolved Question
 
 * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules.
-  This is the approach IntelliJ Rust is taking.
+  This is the approach IntelliJ Rust is takeing.
   However, experience shows that super module (which generally has a feeling of navigation between files) should be separate.
-  If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising.
+  If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising.
 
 ## Join Lines
 
@@ -193,7 +193,7 @@ fn main() {
 ### Unresolved Question
 
 * What is the position of the cursor after `joinLines`?
-  Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets.
+  Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets.
   However, it then becomes unclear how it works with multi cursor.
 
 ## On Enter
@@ -330,7 +330,7 @@ Moreover, it would be cool if editors didn't need to implement even basic langua
 
 ### Unresolved Question
 
-* Should we return a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair?
+* Should we return a a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair?
   This is how `SelectionRange` request works.
 * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs?
 
@@ -511,7 +511,7 @@ Expands macro call at a given position.
 This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types.
 Generally, the client should re-query inlay hints after every modification.
 Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one.
-Upstream issues: https://github.com/microsoft/language-server-protocol/issues/956 , https://github.com/rust-analyzer/rust-analyzer/issues/2797
+Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956
 
 **Request:**
 
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 468dedff20..48ce4b92a6 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -53,9 +53,9 @@ https://www.tedinski.com/2018/02/06/system-boundaries.html
 ## Crates.io Dependencies
 
 We try to be very conservative with usage of crates.io dependencies.
-Don't use small "helper" crates (exception: `itertools` and `either` are allowed).
+Don't use small "helper" crates (exception: `itertools` is allowed).
 If there's some general reusable bit of code you need, consider adding it to the `stdx` crate.
-A useful exercise is to read Cargo.lock and see if some *transitive* dependencies do not make sense for rust-analyzer.
+A useful exercise is to read Cargo.lock and see if some of the *transitive* dependencies do not make sense for rust-analyzer.
 
 **Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break.
 
@@ -330,7 +330,7 @@ When implementing `do_thing`, it might be very useful to create a context object
 
 ```rust
 pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res {
-    let mut ctx = Ctx { arg1, arg2 };
+    let mut ctx = Ctx { arg1, arg2 }
     ctx.run()
 }
 
@@ -586,7 +586,7 @@ use super::{}
 
 **Rationale:** consistency.
 Reading order is important for new contributors.
-Grouping by crate allows spotting unwanted dependencies easier.
+Grouping by crate allows to spot unwanted dependencies easier.
 
 ## Import Style
 
@@ -779,7 +779,7 @@ assert!(x < y);
 assert!(x > 0);
 
 // BAD
-assert!(x >= lo && x <= hi);
+assert!(x >= lo && x <= hi>);
 assert!(r1 < l2 || l1 > r2);
 assert!(y > x);
 assert!(0 > x);
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md
index f7a0c09fc1..737cc7a729 100644
--- a/docs/dev/syntax.md
+++ b/docs/dev/syntax.md
@@ -145,7 +145,7 @@ Another alternative (used by swift and roslyn) is to explicitly divide the set o
 
 ```rust
 struct Token {
-    kind: NonTriviaTokenKind,
+    kind: NonTriviaTokenKind
     text: String,
     leading_trivia: Vec<TriviaToken>,
     trailing_trivia: Vec<TriviaToken>,
@@ -240,7 +240,7 @@ impl SyntaxNode {
             let child_offset = offset;
             offset += green_child.text_len;
             Arc::new(SyntaxData {
-                offset: child_offset,
+                offset: child_offset;
                 parent: Some(Arc::clone(self)),
                 green: Arc::clone(green_child),
             })
@@ -249,7 +249,7 @@ impl SyntaxNode {
 }
 
 impl PartialEq for SyntaxNode {
-    fn eq(&self, other: &SyntaxNode) -> bool {
+    fn eq(&self, other: &SyntaxNode) {
         self.offset == other.offset
             && Arc::ptr_eq(&self.green, &other.green)
     }
@@ -273,7 +273,7 @@ This is OK because trees traversals mostly (always, in case of rust-analyzer) ru
 The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range.
 You can also use the similar trick to store a `SyntaxNode`.
 That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`.
-However, rust-analyzer goes even further.
+However rust-analyzer goes even further.
 It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`.
 The `SyntaxNode` is the restored by reparsing the file and traversing it from root.
 With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage.


Test patch:
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 4b2c82b417..61f18b0d20 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1292,25 +1292,3 @@ mod b {
         "#]],
     )
 }
-
-#[test]
-fn impl_in_unnamed_const() {
-    check_types(
-        r#"
-struct S;
-
-trait Tr {
-    fn method(&self) -> u16;
-}
-
-const _: () = {
-    impl Tr for S {}
-};
-
-fn f() {
-    S.method();
-  //^^^^^^^^^^ u16
-}
-    "#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 361cd63026..84c5c05fd3 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2564,3 +2564,36 @@ fn f() {
     "#,
     )
 }
+
+#[test]
+fn infer_type_alias_variant() {
+    check_infer(
+        r#"
+type Qux = Foo;
+enum Foo {
+    Bar(i32),
+    Baz { baz: f32 }
+}
+
+fn f() {
+    match Foo::Bar(3) {
+        Qux::Bar(bar) => (),
+        Qux::Baz { baz } => (),
+    }
+}
+    "#,
+        expect![[r#"
+            72..166 '{     ...   } }': ()
+            78..164 'match ...     }': ()
+            84..92 'Foo::Bar': Bar(i32) -> Foo
+            84..95 'Foo::Bar(3)': Foo
+            93..94 '3': i32
+            106..119 'Qux::Bar(bar)': Foo
+            115..118 'bar': i32
+            123..125 '()': ()
+            135..151 'Qux::B... baz }': Foo
+            146..149 'baz': f32
+            155..157 '()': ()
+        "#]],
+    )
+}
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs
index 099baeca2f..6bc824e943 100644
--- a/crates/test_utils/src/fixture.rs
+++ b/crates/test_utils/src/fixture.rs
@@ -1,65 +1,5 @@
 //! Defines `Fixture` -- a convenient way to describe the initial state of
 //! rust-analyzer database from a single string.
-//!
-//! Fixtures are strings containing rust source code with optional metadata.
-//! A fixture without metadata is parsed into a single source file.
-//! Use this to test functionality local to one file.
-//!
-//! Simple Example:
-//! ```
-//! r#"
-//! fn main() {
-//!     println!("Hello World")
-//! }
-//! "#
-//! ```
-//!
-//! Metadata can be added to a fixture after a `//-` comment.
-//! The basic form is specifying filenames,
-//! which is also how to define multiple files in a single test fixture
-//!
-//! Example using two files in the same crate:
-//! ```
-//! "
-//! //- /main.rs
-//! mod foo;
-//! fn main() {
-//!     foo::bar();
-//! }
-//!
-//! //- /foo.rs
-//! pub fn bar() {}
-//! "
-//! ```
-//!
-//! Example using two crates with one file each, with one crate depending on the other:
-//! ```
-//! r#"
-//! //- /main.rs crate:a deps:b
-//! fn main() {
-//!     b::foo();
-//! }
-//! //- /lib.rs crate:b
-//! pub fn b() {
-//!     println!("Hello World")
-//! }
-//! "#
-//! ```
-//!
-//! Metadata allows specifying all settings and variables
-//! that are available in a real rust project:
-//! - crate names via `crate:cratename`
-//! - dependencies via `deps:dep1,dep2`
-//! - configuration settings via `cfg:dbg=false,opt_level=2`
-//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
-//!
-//! Example using all available metadata:
-//! ```
-//! "
-//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
-//! fn insert_source_code_here() {}
-//! "
-//! ```
 
 use rustc_hash::FxHashMap;
 use stdx::{lines_with_ends, split_once, trim_indent};
@@ -84,7 +24,7 @@ impl Fixture {
     ///  //- some meta
     ///  line 1
     ///  line 2
-    ///  //- other meta
+    ///  // - other meta
     ///  ```
     pub fn parse(ra_fixture: &str) -> Vec<Fixture> {
         let fixture = trim_indent(ra_fixture);