@@ -1969,28 +1969,51 @@ 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 assigned_tys = match assigned_ty {
2009
+ Some ( Type :: Tuple ( tuple) ) => {
2010
+ Either :: Left ( tuple. elements ( self . db ( ) ) . into_iter ( ) . copied ( ) )
2011
+ }
2012
+ Some ( _) | None => Either :: Right ( std:: iter:: empty ( ) ) ,
2013
+ } ;
2014
+
1989
2015
for element in elts {
1990
- self . infer_target ( element, value) ;
1991
- }
1992
- if elts. is_empty ( ) {
1993
- self . infer_standalone_expression ( value) ;
2016
+ self . infer_target_impl ( element, assigned_tys. next ( ) ) ;
1994
2017
}
1995
2018
}
1996
2019
ast:: Expr :: Attribute (
@@ -1999,18 +2022,22 @@ impl<'db> TypeInferenceBuilder<'db> {
1999
2022
..
2000
2023
} ,
2001
2024
) => {
2002
- let lhs_ty = self . infer_attribute_expression ( lhs_expr) ;
2003
- self . store_expression_type ( target, lhs_ty ) ;
2025
+ let attribute_expr_ty = self . infer_attribute_expression ( lhs_expr) ;
2026
+ self . store_expression_type ( target, attribute_expr_ty ) ;
2004
2027
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) ;
2028
+ if let Some ( assigned_ty) = assigned_ty {
2029
+ if !assigned_ty. is_assignable_to ( self . db ( ) , attribute_expr_ty) {
2030
+ report_invalid_assignment (
2031
+ & self . context ,
2032
+ target. into ( ) ,
2033
+ attribute_expr_ty,
2034
+ assigned_ty,
2035
+ ) ;
2036
+ }
2009
2037
}
2010
2038
}
2011
2039
_ => {
2012
2040
// TODO: Remove this once we handle all possible assignment targets.
2013
- self . infer_standalone_expression ( value) ;
2014
2041
self . infer_expression ( target) ;
2015
2042
}
2016
2043
}
@@ -2279,7 +2306,10 @@ impl<'db> TypeInferenceBuilder<'db> {
2279
2306
is_async : _,
2280
2307
} = for_statement;
2281
2308
2282
- self . infer_target ( target, iter) ;
2309
+ self . infer_target ( target, iter, |db, iter_ty| {
2310
+ iter_ty. iterate ( db) . unwrap_without_diagnostic ( )
2311
+ } ) ;
2312
+
2283
2313
self . infer_body ( body) ;
2284
2314
self . infer_body ( orelse) ;
2285
2315
}
0 commit comments