Skip to content

Commit bed30a7

Browse files
committed
Fix issues about assigning typed properties
1 parent b6b8ebd commit bed30a7

37 files changed

+235
-17
lines changed

src/Analyser/NodeScopeResolver.php

+6-16
Original file line numberDiff line numberDiff line change
@@ -5556,15 +5556,10 @@ static function (): void {
55565556
$assignedExprType = $scope->getType($assignedExpr);
55575557
$nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope);
55585558
if ($propertyReflection->canChangeTypeAfterAssignment()) {
5559-
if ($propertyReflection->hasNativeType()) {
5559+
if ($propertyReflection->hasNativeType() && $scope->isDeclareStrictTypes()) {
55605560
$propertyNativeType = $propertyReflection->getNativeType();
5561-
if ($propertyNativeType->isSuperTypeOf($assignedExprType)->yes()) {
5562-
$assignedExprNativeType = $scope->getNativeType($assignedExpr);
5563-
if (!$propertyNativeType->isSuperTypeOf($assignedExprNativeType)->yes()) {
5564-
$assignedExprNativeType = $propertyNativeType;
5565-
}
5566-
$scope = $scope->assignExpression($var, $assignedExprType, $assignedExprNativeType);
5567-
}
5561+
5562+
$scope = $scope->assignExpression($var, TypeCombinator::intersect($assignedExprType->toCoercedArgumentType(true), $propertyNativeType), TypeCombinator::intersect($scope->getNativeType($assignedExpr)->toCoercedArgumentType(true), $propertyNativeType));
55685563
} else {
55695564
$scope = $scope->assignExpression($var, $assignedExprType, $scope->getNativeType($assignedExpr));
55705565
}
@@ -5632,15 +5627,10 @@ static function (): void {
56325627
$assignedExprType = $scope->getType($assignedExpr);
56335628
$nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope);
56345629
if ($propertyReflection !== null && $propertyReflection->canChangeTypeAfterAssignment()) {
5635-
if ($propertyReflection->hasNativeType()) {
5630+
if ($propertyReflection->hasNativeType() && $scope->isDeclareStrictTypes()) {
56365631
$propertyNativeType = $propertyReflection->getNativeType();
5637-
if ($propertyNativeType->isSuperTypeOf($assignedExprType)->yes()) {
5638-
$assignedExprNativeType = $scope->getNativeType($assignedExpr);
5639-
if (!$propertyNativeType->isSuperTypeOf($assignedExprNativeType)->yes()) {
5640-
$assignedExprNativeType = $propertyNativeType;
5641-
}
5642-
$scope = $scope->assignExpression($var, $assignedExprType, $assignedExprNativeType);
5643-
}
5632+
5633+
$scope = $scope->assignExpression($var, TypeCombinator::intersect($assignedExprType->toCoercedArgumentType(true), $propertyNativeType), TypeCombinator::intersect($scope->getNativeType($assignedExpr)->toCoercedArgumentType(true), $propertyNativeType));
56445634
} else {
56455635
$scope = $scope->assignExpression($var, $assignedExprType, $scope->getNativeType($assignedExpr));
56465636
}

src/Type/Accessory/AccessoryArrayListType.php

+5
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@ public function toArrayKey(): Type
469469
return new ErrorType();
470470
}
471471

472+
public function toCoercedArgumentType(bool $strictTypes): Type
473+
{
474+
return $this;
475+
}
476+
472477
public function traverse(callable $cb): Type
473478
{
474479
return $this;

src/Type/Accessory/AccessoryLiteralStringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ public function toArrayKey(): Type
213213
return $this;
214214
}
215215

216+
public function toCoercedArgumentType(bool $strictTypes): Type
217+
{
218+
return $this;
219+
}
220+
216221
public function isNull(): TrinaryLogic
217222
{
218223
return TrinaryLogic::createNo();

src/Type/Accessory/AccessoryLowercaseStringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ public function toArrayKey(): Type
210210
return $this;
211211
}
212212

213+
public function toCoercedArgumentType(bool $strictTypes): Type
214+
{
215+
return $this;
216+
}
217+
213218
public function isNull(): TrinaryLogic
214219
{
215220
return TrinaryLogic::createNo();

src/Type/Accessory/AccessoryNonEmptyStringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ public function toArrayKey(): Type
211211
return $this;
212212
}
213213

214+
public function toCoercedArgumentType(bool $strictTypes): Type
215+
{
216+
return $this;
217+
}
218+
214219
public function isNull(): TrinaryLogic
215220
{
216221
return TrinaryLogic::createNo();

src/Type/Accessory/AccessoryNonFalsyStringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ public function toArrayKey(): Type
212212
return $this;
213213
}
214214

215+
public function toCoercedArgumentType(bool $strictTypes): Type
216+
{
217+
return $this;
218+
}
219+
215220
public function isNull(): TrinaryLogic
216221
{
217222
return TrinaryLogic::createNo();

src/Type/Accessory/AccessoryNumericStringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ public function toArrayKey(): Type
213213
return new IntegerType();
214214
}
215215

216+
public function toCoercedArgumentType(bool $strictTypes): Type
217+
{
218+
return $this;
219+
}
220+
216221
public function isNull(): TrinaryLogic
217222
{
218223
return TrinaryLogic::createNo();

src/Type/Accessory/AccessoryUppercaseStringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ public function toArrayKey(): Type
210210
return $this;
211211
}
212212

213+
public function toCoercedArgumentType(bool $strictTypes): Type
214+
{
215+
return $this;
216+
}
217+
213218
public function isNull(): TrinaryLogic
214219
{
215220
return TrinaryLogic::createNo();

src/Type/Accessory/HasOffsetType.php

+5
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,11 @@ public function toArrayKey(): Type
388388
return new ErrorType();
389389
}
390390

391+
public function toCoercedArgumentType(bool $strictTypes): Type
392+
{
393+
return $this;
394+
}
395+
391396
public function getEnumCases(): array
392397
{
393398
return [];

src/Type/Accessory/HasOffsetValueType.php

+5
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,11 @@ public function toArrayKey(): Type
438438
return new ErrorType();
439439
}
440440

441+
public function toCoercedArgumentType(bool $strictTypes): Type
442+
{
443+
return $this;
444+
}
445+
441446
public function getEnumCases(): array
442447
{
443448
return [];

src/Type/Accessory/NonEmptyArrayType.php

+5
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,11 @@ public function toArrayKey(): Type
445445
return new ErrorType();
446446
}
447447

448+
public function toCoercedArgumentType(bool $strictTypes): Type
449+
{
450+
return $this;
451+
}
452+
448453
public function traverse(callable $cb): Type
449454
{
450455
return $this;

src/Type/Accessory/OversizedArrayType.php

+5
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,11 @@ public function toArrayKey(): Type
429429
return new ErrorType();
430430
}
431431

432+
public function toCoercedArgumentType(bool $strictTypes): Type
433+
{
434+
return $this;
435+
}
436+
432437
public function traverse(callable $cb): Type
433438
{
434439
return $this;

src/Type/BooleanType.php

+5
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ public function toArrayKey(): Type
111111
return new UnionType([new ConstantIntegerType(0), new ConstantIntegerType(1)]);
112112
}
113113

114+
public function toCoercedArgumentType(bool $strictTypes): Type
115+
{
116+
return $this;
117+
}
118+
114119
public function isOffsetAccessLegal(): TrinaryLogic
115120
{
116121
return TrinaryLogic::createYes();

src/Type/CallableType.php

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Type;
44

5+
use Closure;
56
use PHPStan\Analyser\OutOfClassScope;
67
use PHPStan\Php\PhpVersion;
78
use PHPStan\PhpDoc\Tag\TemplateTag;
@@ -321,6 +322,11 @@ public function toArrayKey(): Type
321322
return new ErrorType();
322323
}
323324

325+
public function toCoercedArgumentType(bool $strictTypes): Type
326+
{
327+
return TypeCombinator::union($this, new StringType(), new ArrayType(new MixedType(true), new MixedType(true)), new ObjectType(Closure::class));
328+
}
329+
324330
public function isOffsetAccessLegal(): TrinaryLogic
325331
{
326332
return TrinaryLogic::createMaybe();

src/Type/ClosureType.php

+5
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,11 @@ public function toArrayKey(): Type
462462
return new ErrorType();
463463
}
464464

465+
public function toCoercedArgumentType(bool $strictTypes): Type
466+
{
467+
return TypeCombinator::union($this, new CallableType());
468+
}
469+
465470
public function getTemplateTypeMap(): TemplateTypeMap
466471
{
467472
return $this->templateTypeMap;

src/Type/Constant/ConstantBooleanType.php

+5
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ public function toArrayKey(): Type
107107
return new ConstantIntegerType((int) $this->value);
108108
}
109109

110+
public function toCoercedArgumentType(bool $strictTypes): Type
111+
{
112+
return $this;
113+
}
114+
110115
public function isTrue(): TrinaryLogic
111116
{
112117
return TrinaryLogic::createFromBoolean($this->value === true);

src/Type/FloatType.php

+5
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ public function toArrayKey(): Type
143143
return new IntegerType();
144144
}
145145

146+
public function toCoercedArgumentType(bool $strictTypes): Type
147+
{
148+
return $this;
149+
}
150+
146151
public function isOffsetAccessLegal(): TrinaryLogic
147152
{
148153
return TrinaryLogic::createYes();

src/Type/Generic/TemplateTypeTrait.php

+5
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ public function toArrayKey(): Type
250250
return $this;
251251
}
252252

253+
public function toCoercedArgumentType(bool $strictTypes): Type
254+
{
255+
return $this;
256+
}
257+
253258
public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
254259
{
255260
if (

src/Type/IntegerType.php

+5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ public function toArrayKey(): Type
9898
return $this;
9999
}
100100

101+
public function toCoercedArgumentType(bool $strictTypes): Type
102+
{
103+
return TypeCombinator::union($this, $this->toFloat());
104+
}
105+
101106
public function isOffsetAccessLegal(): TrinaryLogic
102107
{
103108
return TrinaryLogic::createYes();

src/Type/IntersectionType.php

+5
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,11 @@ public function toArrayKey(): Type
10621062
return $this->intersectTypes(static fn (Type $type): Type => $type->toArrayKey());
10631063
}
10641064

1065+
public function toCoercedArgumentType(bool $strictTypes): Type
1066+
{
1067+
return $this->intersectTypes(static fn (Type $type): Type => $type->toCoercedArgumentType($strictTypes));
1068+
}
1069+
10651070
public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
10661071
{
10671072
$types = TemplateTypeMap::createEmpty();

src/Type/IterableType.php

+5
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,11 @@ public function toArrayKey(): Type
234234
return new ErrorType();
235235
}
236236

237+
public function toCoercedArgumentType(bool $strictTypes): Type
238+
{
239+
return TypeCombinator::union($this, new ArrayType(new MixedType(true), new MixedType(true)), new ObjectType(Traversable::class));
240+
}
241+
237242
public function isOffsetAccessLegal(): TrinaryLogic
238243
{
239244
return TrinaryLogic::createMaybe();

src/Type/MixedType.php

+5
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,11 @@ public function toArrayKey(): Type
580580
return new BenevolentUnionType([new IntegerType(), new StringType()]);
581581
}
582582

583+
public function toCoercedArgumentType(bool $strictTypes): Type
584+
{
585+
return $this;
586+
}
587+
583588
public function isIterable(): TrinaryLogic
584589
{
585590
if ($this->subtractedType !== null) {

src/Type/NeverType.php

+5
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ public function toArrayKey(): Type
383383
return $this;
384384
}
385385

386+
public function toCoercedArgumentType(bool $strictTypes): Type
387+
{
388+
return $this;
389+
}
390+
386391
public function traverse(callable $cb): Type
387392
{
388393
return $this;

src/Type/NonexistentParentClassType.php

+5
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ public function toArrayKey(): Type
157157
return new ErrorType();
158158
}
159159

160+
public function toCoercedArgumentType(bool $strictTypes): Type
161+
{
162+
return new ErrorType();
163+
}
164+
160165
public function isOffsetAccessLegal(): TrinaryLogic
161166
{
162167
return TrinaryLogic::createNo();

src/Type/NullType.php

+5
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ public function toArrayKey(): Type
166166
return new ConstantStringType('');
167167
}
168168

169+
public function toCoercedArgumentType(bool $strictTypes): Type
170+
{
171+
return $this;
172+
}
173+
169174
public function isOffsetAccessible(): TrinaryLogic
170175
{
171176
return TrinaryLogic::createYes();

src/Type/ObjectType.php

+5
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,11 @@ public function toArrayKey(): Type
671671
return $this->toString();
672672
}
673673

674+
public function toCoercedArgumentType(bool $strictTypes): Type
675+
{
676+
return $this;
677+
}
678+
674679
public function toBoolean(): BooleanType
675680
{
676681
if ($this->isInstanceOf('SimpleXMLElement')->yes()) {

src/Type/ResourceType.php

+5
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ public function toArrayKey(): Type
9191
return new ErrorType();
9292
}
9393

94+
public function toCoercedArgumentType(bool $strictTypes): Type
95+
{
96+
return $this;
97+
}
98+
9499
public function isOffsetAccessLegal(): TrinaryLogic
95100
{
96101
return TrinaryLogic::createYes();

src/Type/StaticType.php

+5
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,11 @@ public function toArrayKey(): Type
646646
return $this->getStaticObjectType()->toArrayKey();
647647
}
648648

649+
public function toCoercedArgumentType(bool $strictTypes): Type
650+
{
651+
return $this->getStaticObjectType()->toCoercedArgumentType($strictTypes);
652+
}
653+
649654
public function toBoolean(): BooleanType
650655
{
651656
return $this->getStaticObjectType()->toBoolean();

src/Type/StrictMixedType.php

+5
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,11 @@ public function toArrayKey(): Type
395395
return new ErrorType();
396396
}
397397

398+
public function toCoercedArgumentType(bool $strictTypes): Type
399+
{
400+
return $this;
401+
}
402+
398403
public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
399404
{
400405
return TemplateTypeMap::createEmpty();

src/Type/StringType.php

+5
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ public function toArrayKey(): Type
181181
return $this;
182182
}
183183

184+
public function toCoercedArgumentType(bool $strictTypes): Type
185+
{
186+
return $this;
187+
}
188+
184189
public function isNull(): TrinaryLogic
185190
{
186191
return TrinaryLogic::createNo();

0 commit comments

Comments
 (0)