Skip to content

Commit

Permalink
Reimplemented contextual inference 1
Browse files Browse the repository at this point in the history
  • Loading branch information
klimick committed Dec 3, 2023
1 parent f96ec4d commit 507ef51
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/Psalm/ContextualTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ public function fillTemplateResult(Union $input_type): void
$input_type,
);
}

public function getTemplateResult(): TemplateResult
{
return $this->template_result;
}
}
6 changes: 5 additions & 1 deletion src/Psalm/Internal/Analyzer/ClosureAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,12 @@ public static function analyzeExpression(
$statements_analyzer->getSource()->inferred_has_mutation = true;
}

if (!$statements_analyzer->node_data->getType($stmt)) {
$inferred_closure_type = $statements_analyzer->node_data->getType($stmt);

if ($inferred_closure_type === null) {
$statements_analyzer->node_data->setType($stmt, Type::getClosure());
} elseif ($context->contextual_type_resolver !== null) {
$context->contextual_type_resolver->fillTemplateResult($inferred_closure_type);
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,13 @@ public static function analyze(
$args = array_reverse($args, true);
}

$has_packed_var = false;

foreach ($args as $argument_offset => $arg) {
if ($arg->unpack) {
$has_packed_var = true;
}

if ($function_params === null) {
if (self::evaluateArbitraryParam(
$statements_analyzer,
Expand Down Expand Up @@ -239,6 +245,17 @@ public static function analyze(
return false;
}

if (!$arg->value instanceof PhpParser\Node\Expr\Closure
&& !$arg->value instanceof PhpParser\Node\Expr\ArrowFunction
&& $context->contextual_type_resolver !== null
) {
$inferred_arg_type = $statements_analyzer->node_data->getType($arg->value);

if ($inferred_arg_type !== null) {
$context->contextual_type_resolver->fillTemplateResult($inferred_arg_type);
}
}

$context->inside_call = $was_inside_call;
$context->contextual_type_resolver = $was_contextual_type_resolver;

Expand All @@ -260,6 +277,42 @@ public static function analyze(
}
}

if ($context->contextual_type_resolver !== null
&& $function_params !== null
&& count($function_params) > count($args)
&& !$has_packed_var
) {
for ($i = count($args), $iMax = count($function_params); $i < $iMax; $i++) {
if (isset($function_params[$i])
&& $function_params[$i]->default_type
&& $function_params[$i]->type
&& $function_params[$i]->type->hasTemplate()
) {
if ($function_params[$i]->default_type instanceof Union) {
$default_type = $function_params[$i]->default_type;
} else {
$default_type_atomic = ConstantTypeResolver::resolve(
$statements_analyzer->getCodebase()->classlikes,
$function_params[$i]->default_type,
$statements_analyzer,
);

$default_type = new Union([$default_type_atomic]);
}

if ($default_type->hasLiteralValue()) {
$was_contextual_type_resolver = $context->contextual_type_resolver;

$context->contextual_type_resolver = $context->contextual_type_resolver
->withContextualType($function_params[$i]->type);
$context->contextual_type_resolver->fillTemplateResult($default_type);

$context->contextual_type_resolver = $was_contextual_type_resolver;
}
}
}
}

if ($method_id === "ReflectionClass::getattributes"
|| $method_id === "ReflectionClassConstant::getattributes"
|| $method_id === "ReflectionFunction::getattributes"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ public static function analyze(
);
}

$template_result = $context->contextual_type_resolver->getTemplateResult();
$context->contextual_type_resolver = $was_contextual_resolver;

if ($function_name instanceof PhpParser\Node\Name && $function_call_info->function_id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,17 +195,17 @@ public static function analyze(
);
}

$was_contextual_type_resolver = $context->contextual_type_resolver;
$context->contextual_type_resolver = CallLikeContextualTypeExtractor::extract(
$context,
$codebase,
$method_storage,
$collected_argument_templates,
);

$is_first_class_callable = $stmt->isFirstClassCallable();

if (!$is_first_class_callable) {
$was_contextual_type_resolver = $context->contextual_type_resolver;
$context->contextual_type_resolver = CallLikeContextualTypeExtractor::extract(
$context,
$codebase,
$method_storage,
$collected_argument_templates,
);

if (self::checkMethodArgs(
$method_id,
$args,
Expand All @@ -218,10 +218,11 @@ public static function analyze(

return Type::getMixed();
}

$context->contextual_type_resolver = $was_contextual_type_resolver;
}

$template_result = $context->contextual_type_resolver->getTemplateResult();
$context->contextual_type_resolver = $was_contextual_type_resolver;

$return_type_candidate = MethodCallReturnTypeFetcher::fetch(
$statements_analyzer,
$codebase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,6 @@ public static function handleMagicMethod(
$context,
);

$context->contextual_type_resolver = $was_contextual_type_resolver;

$template_result = new TemplateResult(
$collected_argument_templates->template_types,
$collected_argument_templates->lower_bounds,
Expand All @@ -164,6 +162,9 @@ public static function handleMagicMethod(
$context,
);

$template_result = $context->contextual_type_resolver->getTemplateResult();
$context->contextual_type_resolver = $was_contextual_type_resolver;

if ($pseudo_method_storage->return_type) {
$return_type_candidate = $pseudo_method_storage->return_type;

Expand Down Expand Up @@ -326,8 +327,6 @@ public static function handleMissingOrMagicMethod(
return;
}

$context->contextual_type_resolver = $was_contextual_type_resolver;

$template_result = new TemplateResult(
$collected_argument_templates->template_types,
$collected_argument_templates->lower_bounds,
Expand All @@ -347,6 +346,9 @@ public static function handleMissingOrMagicMethod(
return;
}

$template_result = $context->contextual_type_resolver->getTemplateResult();
$context->contextual_type_resolver = $was_contextual_type_resolver;

if ($pseudo_method_storage->return_type) {
$return_type_candidate = $pseudo_method_storage->return_type;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public static function analyze(
return;
}

$template_result = $context->contextual_type_resolver->getTemplateResult();
$context->contextual_type_resolver = $was_contextual_type_resolver;

$fq_class_name = $stmt->class instanceof PhpParser\Node\Name && $stmt->class->getParts() === ['parent']
Expand Down
8 changes: 0 additions & 8 deletions src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,6 @@ public static function analyze(
return false;
}

if ($context->contextual_type_resolver !== null) {
$inferred_type = $statements_analyzer->node_data->getType($stmt);

if ($inferred_type !== null) {
$context->contextual_type_resolver->fillTemplateResult($inferred_type);
}
}

return true;
}

Expand Down

0 comments on commit 507ef51

Please sign in to comment.