@@ -1973,24 +1973,46 @@ impl<'db> TypeInferenceBuilder<'db> {
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.
1980
1981
///
1981
1982
/// # Panics
1982
1983
///
1983
1984
/// If the `value` is not a standalone expression.
1984
1985
fn infer_target ( & mut self , target : & ast:: Expr , value : & ast:: Expr ) {
1986
+ let check_assignment_ty = match target {
1987
+ ast:: Expr :: Name ( _) => None ,
1988
+ _ => Some ( self . infer_standalone_expression ( value) ) ,
1989
+ } ;
1990
+ self . infer_target_and_check_assignment ( target, check_assignment_ty) ;
1991
+ }
1992
+
1993
+ /// Similar to [`infer_target`], but with a custom type to check the assignment against.
1994
+ fn infer_target_and_check_assignment (
1995
+ & mut self ,
1996
+ target : & ast:: Expr ,
1997
+ check_assignment_ty : Option < Type < ' db > > ,
1998
+ ) {
1985
1999
match target {
1986
2000
ast:: Expr :: Name ( name) => self . infer_definition ( name) ,
1987
2001
ast:: Expr :: List ( ast:: ExprList { elts, .. } )
1988
2002
| ast:: Expr :: Tuple ( ast:: ExprTuple { elts, .. } ) => {
2003
+ let mut check_assignment_tys: Box < dyn Iterator < Item = Type > > =
2004
+ match check_assignment_ty {
2005
+ Some ( Type :: Tuple ( tuple) ) => {
2006
+ Box :: new ( tuple. elements ( self . db ( ) ) . into_iter ( ) . copied ( ) )
2007
+ }
2008
+ Some ( ty) => Box :: new ( std:: iter:: repeat (
2009
+ ty. iterate ( self . db ( ) ) . unwrap_without_diagnostic ( ) ,
2010
+ ) ) ,
2011
+ None => Box :: new ( std:: iter:: empty ( ) ) ,
2012
+ } ;
2013
+
1989
2014
for element in elts {
1990
- self . infer_target ( element, value) ;
1991
- }
1992
- if elts. is_empty ( ) {
1993
- self . infer_standalone_expression ( value) ;
2015
+ self . infer_target_and_check_assignment ( element, check_assignment_tys. next ( ) ) ;
1994
2016
}
1995
2017
}
1996
2018
ast:: Expr :: Attribute (
@@ -2002,15 +2024,14 @@ impl<'db> TypeInferenceBuilder<'db> {
2002
2024
let lhs_ty = self . infer_attribute_expression ( lhs_expr) ;
2003
2025
self . store_expression_type ( target, lhs_ty) ;
2004
2026
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 ) ;
2027
+ if let Some ( rhs_ty) = check_assignment_ty {
2028
+ if !rhs_ty . is_assignable_to ( self . db ( ) , lhs_ty ) {
2029
+ report_invalid_assignment ( & self . context , target . into ( ) , lhs_ty, rhs_ty ) ;
2030
+ }
2009
2031
}
2010
2032
}
2011
2033
_ => {
2012
2034
// TODO: Remove this once we handle all possible assignment targets.
2013
- self . infer_standalone_expression ( value) ;
2014
2035
self . infer_expression ( target) ;
2015
2036
}
2016
2037
}
@@ -2279,7 +2300,16 @@ impl<'db> TypeInferenceBuilder<'db> {
2279
2300
is_async : _,
2280
2301
} = for_statement;
2281
2302
2282
- self . infer_target ( target, iter) ;
2303
+ let check_assignment_ty = match target. as_ref ( ) {
2304
+ ast:: Expr :: Name ( _) => None , // Check will be done in `infer_definition`
2305
+ _ => {
2306
+ let iterable_ty = self . infer_standalone_expression ( iter) ;
2307
+ let iterator_ty = iterable_ty. iterate ( self . db ( ) ) . unwrap_without_diagnostic ( ) ;
2308
+ Some ( iterator_ty)
2309
+ }
2310
+ } ;
2311
+ self . infer_target_and_check_assignment ( target, check_assignment_ty) ;
2312
+
2283
2313
self . infer_body ( body) ;
2284
2314
self . infer_body ( orelse) ;
2285
2315
}
0 commit comments