@@ -294,6 +294,77 @@ public function enterDeclareStrictTypes(): self
294294 );
295295 }
296296
297+ /**
298+ * @param array<string, ExpressionTypeHolder> $currentExpressionTypes
299+ * @return array<string, ExpressionTypeHolder>
300+ */
301+ private function rememberConstructorExpressions (array $ currentExpressionTypes ): array
302+ {
303+ $ expressionTypes = [];
304+ foreach ($ currentExpressionTypes as $ exprString => $ expressionTypeHolder ) {
305+ $ expr = $ expressionTypeHolder ->getExpr ();
306+ if ($ expr instanceof FuncCall) {
307+ if (
308+ !$ expr ->name instanceof Name
309+ || !in_array ($ expr ->name ->name , ['class_exists ' , 'function_exists ' ], true )
310+ ) {
311+ continue ;
312+ }
313+ } elseif ($ expr instanceof PropertyFetch) {
314+ if (
315+ !$ expr ->name instanceof Node \Identifier
316+ || !$ expr ->var instanceof Variable
317+ || $ expr ->var ->name !== 'this '
318+ || !$ this ->phpVersion ->supportsReadOnlyProperties ()
319+ ) {
320+ continue ;
321+ }
322+
323+ $ propertyReflection = $ this ->propertyReflectionFinder ->findPropertyReflectionFromNode ($ expr , $ this );
324+ if ($ propertyReflection === null ) {
325+ continue ;
326+ }
327+
328+ $ nativePropertyReflection = $ propertyReflection ->getNativeReflection ();
329+ if ($ nativePropertyReflection === null || !$ nativePropertyReflection ->isReadOnly ()) {
330+ continue ;
331+ }
332+ } elseif (!$ expr instanceof ConstFetch && !$ expr instanceof PropertyInitializationExpr) {
333+ continue ;
334+ }
335+
336+ $ expressionTypes [$ exprString ] = $ expressionTypeHolder ;
337+ }
338+
339+ if (array_key_exists ('$this ' , $ currentExpressionTypes )) {
340+ $ expressionTypes ['$this ' ] = $ currentExpressionTypes ['$this ' ];
341+ }
342+
343+ return $ expressionTypes ;
344+ }
345+
346+ public function rememberConstructorScope (): self
347+ {
348+ return $ this ->scopeFactory ->create (
349+ $ this ->context ,
350+ $ this ->isDeclareStrictTypes (),
351+ $ this ->getFunction (),
352+ $ this ->getNamespace (),
353+ $ this ->rememberConstructorExpressions ($ this ->expressionTypes ),
354+ $ this ->rememberConstructorExpressions ($ this ->nativeExpressionTypes ),
355+ $ this ->conditionalExpressions ,
356+ $ this ->inClosureBindScopeClasses ,
357+ $ this ->anonymousFunctionReflection ,
358+ $ this ->inFirstLevelStatement ,
359+ [],
360+ [],
361+ $ this ->inFunctionCallsStack ,
362+ $ this ->afterExtractCall ,
363+ $ this ->parentScope ,
364+ $ this ->nativeTypesPromoted ,
365+ );
366+ }
367+
297368 /** @api */
298369 public function isInClass (): bool
299370 {
@@ -3286,7 +3357,7 @@ public function enterFunction(
32863357
32873358 private function enterFunctionLike (
32883359 PhpFunctionFromParserNodeReflection $ functionReflection ,
3289- bool $ preserveThis ,
3360+ bool $ preserveConstructorScope ,
32903361 ): self
32913362 {
32923363 $ parametersByName = [];
@@ -3298,6 +3369,12 @@ private function enterFunctionLike(
32983369 $ expressionTypes = [];
32993370 $ nativeExpressionTypes = [];
33003371 $ conditionalTypes = [];
3372+
3373+ if ($ preserveConstructorScope ) {
3374+ $ expressionTypes = $ this ->rememberConstructorExpressions ($ this ->expressionTypes );
3375+ $ nativeExpressionTypes = $ this ->rememberConstructorExpressions ($ this ->nativeExpressionTypes );
3376+ }
3377+
33013378 foreach ($ functionReflection ->getParameters () as $ parameter ) {
33023379 $ parameterType = $ parameter ->getType ();
33033380
@@ -3348,13 +3425,6 @@ private function enterFunctionLike(
33483425 $ nativeExpressionTypes [$ parameterOriginalValueExprString ] = ExpressionTypeHolder::createYes ($ parameterOriginalValueExpr , $ nativeParameterType );
33493426 }
33503427
3351- if ($ preserveThis && array_key_exists ('$this ' , $ this ->expressionTypes )) {
3352- $ expressionTypes ['$this ' ] = $ this ->expressionTypes ['$this ' ];
3353- }
3354- if ($ preserveThis && array_key_exists ('$this ' , $ this ->nativeExpressionTypes )) {
3355- $ nativeExpressionTypes ['$this ' ] = $ this ->nativeExpressionTypes ['$this ' ];
3356- }
3357-
33583428 return $ this ->scopeFactory ->create (
33593429 $ this ->context ,
33603430 $ this ->isDeclareStrictTypes (),
0 commit comments