fix(ivy): allow abstract directives to have an invalid constructor (#32987)

For abstract directives, i.e. directives without a selector, it may
happen that their constructor is called explicitly from a subclass,
hence its parameters are not required to be valid for Angular's DI
purposes. Prior to this commit however, having an abstract directive
with a constructor that has parameters that are not eligible for
Angular's DI would produce a compilation error.

A similar scenario may occur for `@Injectable`s, where an explicit
`use*` definition allows for the constructor to be irrelevant. For
example, the situation where `useFactory` is specified allows for the
constructor to be called explicitly with any value, so its constructor
parameters are not required to be valid. For `@Injectable`s this is
handled by generating a DI factory function that throws.

This commit implements the same solution for abstract directives, such
that a compilation error is avoided while still producing an error at
runtime if the type is instantiated implicitly by Angular's DI
mechanism.

Fixes #32981

PR Close #32987
This commit is contained in:
JoostK
2019-10-03 21:54:49 +02:00
committed by Andrew Kushnir
parent e4e8dbdee0
commit 8d15bfa6ee
28 changed files with 307 additions and 117 deletions

View File

@ -41,7 +41,7 @@ export interface R3DirectiveMetadata {
/**
* Dependencies of the directive's constructor.
*/
deps: R3DependencyMetadata[]|null;
deps: R3DependencyMetadata[]|'invalid'|null;
/**
* Unparsed selector of the directive, or `null` if there was no selector.

View File

@ -12,17 +12,17 @@ import {CompileReflector} from '../../compile_reflector';
import {BindingForm, convertPropertyBinding} from '../../compiler_util/expression_converter';
import {ConstantPool, DefinitionKind} from '../../constant_pool';
import * as core from '../../core';
import {AST, Interpolation, ParsedEvent, ParsedEventType, ParsedProperty} from '../../expression_parser/ast';
import {AST, ParsedEvent, ParsedEventType, ParsedProperty} from '../../expression_parser/ast';
import {DEFAULT_INTERPOLATION_CONFIG} from '../../ml_parser/interpolation_config';
import * as o from '../../output/output_ast';
import {ParseError, ParseSourceSpan, typeSourceSpan} from '../../parse_util';
import {ParseError, ParseSourceSpan} from '../../parse_util';
import {CssSelector, SelectorMatcher} from '../../selector';
import {ShadowCss} from '../../shadow_css';
import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler';
import {BindingParser} from '../../template_parser/binding_parser';
import {OutputContext, error} from '../../util';
import {BoundEvent} from '../r3_ast';
import {compileFactoryFromMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory';
import {R3FactoryTarget, compileFactoryFunction} from '../r3_factory';
import {Identifiers as R3} from '../r3_identifiers';
import {Render3ParseResult} from '../r3_template_transform';
import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util';
@ -330,7 +330,8 @@ export function compileDirectiveFromRender2(
const meta = directiveMetadataFromGlobalMetadata(directive, outputCtx, reflector);
const res = compileDirectiveFromMetadata(meta, outputCtx.constantPool, bindingParser);
const factoryRes = compileFactoryFromMetadata({...meta, injectFn: R3.directiveInject});
const factoryRes = compileFactoryFunction(
{...meta, injectFn: R3.directiveInject, target: R3FactoryTarget.Directive});
const ngFactoryDefStatement = new o.ClassStmt(
name, null,
[new o.ClassField('ɵfac', o.INFERRED_TYPE, [o.StmtModifier.Static], factoryRes.factory)], [],
@ -382,7 +383,8 @@ export function compileComponentFromRender2(
i18nUseExternalIds: true,
};
const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser);
const factoryRes = compileFactoryFromMetadata({...meta, injectFn: R3.directiveInject});
const factoryRes = compileFactoryFunction(
{...meta, injectFn: R3.directiveInject, target: R3FactoryTarget.Directive});
const ngFactoryDefStatement = new o.ClassStmt(
name, null,
[new o.ClassField('ɵfac', o.INFERRED_TYPE, [o.StmtModifier.Static], factoryRes.factory)], [],