@@ -1969,28 +1969,54 @@ impl<'db> TypeInferenceBuilder<'db> {
1969
1969
} = assignment;
1970
1970
1971
1971
for target in targets {
1972
- self . infer_target ( target, value) ;
1972
+ self . infer_target ( target, value, |_ , ty| ty ) ;
1973
1973
}
1974
1974
}
1975
1975
1976
- /// Infer the definition types involved in a `target` expression.
1976
+ /// Infer the ( definition) types involved in a `target` expression.
1977
1977
///
1978
1978
/// This is used for assignment statements, for statements, etc. with a single or multiple
1979
- /// targets (unpacking).
1979
+ /// targets (unpacking). If `target` is an attribute expression, we check that the assignment
1980
+ /// is valid. For 'target's that are definitions, this check happens elsewhere.
1981
+ ///
1982
+ /// The `to_assigned_ty` function is used to convert the inferred type of the `value` expression
1983
+ /// to the type that is eventually assigned to the `target`.
1980
1984
///
1981
1985
/// # Panics
1982
1986
///
1983
1987
/// If the `value` is not a standalone expression.
1984
- fn infer_target ( & mut self , target : & ast:: Expr , value : & ast:: Expr ) {
1988
+ fn infer_target < F > ( & mut self , target : & ast:: Expr , value : & ast:: Expr , to_assigned_ty : F )
1989
+ where
1990
+ F : Fn ( & ' db dyn Db , Type < ' db > ) -> Type < ' db > ,
1991
+ {
1992
+ let assigned_ty = match target {
1993
+ ast:: Expr :: Name ( _) => None ,
1994
+ _ => {
1995
+ let value_ty = self . infer_standalone_expression ( value) ;
1996
+
1997
+ Some ( to_assigned_ty ( self . db ( ) , value_ty) )
1998
+ }
1999
+ } ;
2000
+ self . infer_target_impl ( target, assigned_ty) ;
2001
+ }
2002
+
2003
+ fn infer_target_impl ( & mut self , target : & ast:: Expr , assigned_ty : Option < Type < ' db > > ) {
1985
2004
match target {
1986
2005
ast:: Expr :: Name ( name) => self . infer_definition ( name) ,
1987
2006
ast:: Expr :: List ( ast:: ExprList { elts, .. } )
1988
2007
| ast:: Expr :: Tuple ( ast:: ExprTuple { elts, .. } ) => {
2008
+ let mut check_assignment_tys: Box < dyn Iterator < Item = Type > > = match assigned_ty {
2009
+ Some ( Type :: Tuple ( tuple) ) => {
2010
+ Box :: new ( tuple. elements ( self . db ( ) ) . into_iter ( ) . copied ( ) )
2011
+ }
2012
+ Some ( ty) => Box :: new ( std:: iter:: repeat (
2013
+ ty. iterate ( self . db ( ) ) . unwrap_without_diagnostic ( ) ,
2014
+ ) ) ,
2015
+ None => Box :: new ( std:: iter:: empty ( ) ) ,
2016
+ } ;
2017
+
1989
2018
for element in elts {
1990
- self . infer_target ( element, value) ;
1991
- }
1992
- if elts. is_empty ( ) {
1993
- self . infer_standalone_expression ( value) ;
2019
+ self . infer_target_impl ( element, check_assignment_tys. next ( ) ) ;
1994
2020
}
1995
2021
}
1996
2022
ast:: Expr :: Attribute (
@@ -2002,15 +2028,14 @@ impl<'db> TypeInferenceBuilder<'db> {
2002
2028
let lhs_ty = self . infer_attribute_expression ( lhs_expr) ;
2003
2029
self . store_expression_type ( target, lhs_ty) ;
2004
2030
2005
- let rhs_ty = self . infer_standalone_expression ( value ) ;
2006
-
2007
- if !rhs_ty . is_assignable_to ( self . db ( ) , lhs_ty) {
2008
- report_invalid_assignment ( & self . context , target . into ( ) , lhs_ty , rhs_ty ) ;
2031
+ if let Some ( rhs_ty) = assigned_ty {
2032
+ if !rhs_ty . is_assignable_to ( self . db ( ) , lhs_ty ) {
2033
+ report_invalid_assignment ( & self . context , target . into ( ) , lhs_ty, rhs_ty ) ;
2034
+ }
2009
2035
}
2010
2036
}
2011
2037
_ => {
2012
2038
// TODO: Remove this once we handle all possible assignment targets.
2013
- self . infer_standalone_expression ( value) ;
2014
2039
self . infer_expression ( target) ;
2015
2040
}
2016
2041
}
@@ -2279,7 +2304,10 @@ impl<'db> TypeInferenceBuilder<'db> {
2279
2304
is_async : _,
2280
2305
} = for_statement;
2281
2306
2282
- self . infer_target ( target, iter) ;
2307
+ self . infer_target ( target, iter, |db, iter_ty| {
2308
+ iter_ty. iterate ( db) . unwrap_without_diagnostic ( )
2309
+ } ) ;
2310
+
2283
2311
self . infer_body ( body) ;
2284
2312
self . infer_body ( orelse) ;
2285
2313
}
0 commit comments