@@ -856,9 +856,8 @@ fn get_fields(
856856 } ,
857857 }
858858 } ,
859- TypeApplication ( constructor, args) => match follow_bindings_in_cache_and_map ( constructor, bindings, cache) {
860- Ref { .. } => get_fields ( & args[ 0 ] , & [ ] , bindings, cache) ,
861- other => get_fields ( & other, args, bindings, cache) ,
859+ TypeApplication ( constructor, args) => {
860+ get_fields ( & follow_bindings_in_cache_and_map ( constructor, bindings, cache) , args, bindings, cache)
862861 } ,
863862 Struct ( fields, rest) => match & cache. type_bindings [ rest. 0 ] {
864863 Bound ( binding) => get_fields ( & binding. clone ( ) , args, bindings, cache) ,
@@ -2007,33 +2006,60 @@ impl<'a> Inferable<'a> for ast::Extern<'a> {
20072006
20082007impl < ' a > Inferable < ' a > for ast:: MemberAccess < ' a > {
20092008 fn infer_impl ( & mut self , cache : & mut ModuleCache < ' a > ) -> TypeResult {
2010- let mut result = infer ( self . lhs . as_mut ( ) , cache) ;
2009+ let result = infer ( self . lhs . as_mut ( ) , cache) ;
20112010
20122011 let level = LetBindingLevel ( CURRENT_LEVEL . load ( Ordering :: SeqCst ) ) ;
20132012 let mut field_type = cache. next_type_variable ( level) ;
20142013
2015- // If this is a mutable reference to a field, ensure the collection is either
2016- // a mutable reference to a collection, or is a local mutable variable.
2017- if let Some ( Mutability :: Mutable ) = self . offset {
2018- let collection_variable = next_type_variable ( cache) ;
2019- let expected = ref_of ( Mutability :: Mutable , collection_variable. clone ( ) , cache) ;
2020-
2021- match try_unify ( & result. typ , & expected, self . lhs . locate ( ) , cache, TE :: ExpectedStructReference ) {
2022- Ok ( bindings) => bindings. perform ( cache) ,
2023- Err ( _) => check_field_access_lhs_is_mutable ( & self . lhs , false , cache) ,
2024- }
2025-
2026- result. typ = collection_variable;
2027- }
2028-
20292014 let mut fields = BTreeMap :: new ( ) ;
20302015 fields. insert ( self . field . clone ( ) , field_type. clone ( ) ) ;
20312016
20322017 // The '..' or 'rest of the struct' stand-in variable
20332018 let rho = cache. next_type_variable_id ( level) ;
20342019 let struct_type = Type :: Struct ( fields, rho) ;
20352020
2036- unify ( & result. typ , & struct_type, self . location , cache, TE :: NoFieldOfType ( self . field . clone ( ) ) ) ;
2021+ let mut bindings =
2022+ try_unify ( & result. typ , & struct_type, self . location , cache, TE :: NoFieldOfType ( self . field . clone ( ) ) ) ;
2023+
2024+ if bindings. is_ok ( ) && self . offset == Some ( Mutability :: Mutable ) {
2025+ // If unification succeeded (`bindings.is_ok()`) and this is a
2026+ // mutable field access (`self.offset == Mutable`), `self.lhs`
2027+ // must be a mutable variable.
2028+ check_field_access_lhs_is_mutable ( self . lhs . as_ref ( ) , false , cache) ;
2029+ } else if let Err ( error_without_deref) = bindings {
2030+ // If unification failed, try again with a single dereference.
2031+ //
2032+ // (This replicates logic from AST-to-HIR monomorphisation.)
2033+
2034+ // If this is a mutable field access (`a.!b`), it's necessary to
2035+ // unify the actual type (`result.typ`) with a mutable reference to
2036+ // the partial `struct_type`.
2037+ let struct_ref = ref_of ( self . offset . unwrap_or ( Mutability :: Immutable ) , struct_type. clone ( ) , cache) ;
2038+
2039+ bindings = try_unify ( & result. typ , & struct_ref, self . lhs . locate ( ) , cache, TE :: ExpectedMutable ) ;
2040+
2041+ // The complicated logic here is solely to improve diagnostics.
2042+ bindings = bindings. map_err ( |error_with_mutable_deref| {
2043+ let struct_imm_ref = ref_of ( Mutability :: Immutable , struct_type. clone ( ) , cache) ;
2044+
2045+ // This unification is only used for a single bit of information.
2046+ let unification_with_immutable_deref =
2047+ try_unify ( & result. typ , & struct_imm_ref, self . lhs . locate ( ) , cache, TE :: ExpectedMutable ) ;
2048+
2049+ if unification_with_immutable_deref. is_ok ( ) {
2050+ // Show TE::ExpectedMutable from the second `try_unify`
2051+ // when an immutable deref unifies but a mutable deref
2052+ // doesn't.
2053+ error_with_mutable_deref
2054+ } else {
2055+ // Unification still fails against an immutable reference.
2056+ // Show the diagnostic that doesn't mention references.
2057+ error_without_deref
2058+ }
2059+ } ) ;
2060+ }
2061+
2062+ perform_bindings_or_push_error ( bindings, cache) ;
20372063
20382064 if let Some ( mutability) = self . offset {
20392065 field_type = ref_of ( mutability, field_type, cache) ;
0 commit comments