[FIR] Support captured type parameters in lightTree2fir

This commit is contained in:
simon.ogorodnik
2020-04-06 23:34:22 +03:00
parent 9db69c0b08
commit 797b58669b
3 changed files with 172 additions and 168 deletions
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.fir.builder package org.jetbrains.kotlin.fir.builder
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import kotlinx.collections.immutable.mutate
import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
@@ -22,11 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.builder.* import org.jetbrains.kotlin.fir.references.builder.*
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.ANONYMOUS_CLASS_ID import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.impl.FirErrorFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
@@ -81,6 +76,10 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
context.capturedTypeParameters.addAll(0, typeParameters.map { typeParameter -> typeParameter.symbol }) context.capturedTypeParameters.addAll(0, typeParameters.map { typeParameter -> typeParameter.symbol })
} }
fun clearCapturedTypeParameters() {
context.capturedTypeParameters = context.capturedTypeParameters.clear()
}
fun callableIdForName(name: Name, local: Boolean = false) = fun callableIdForName(name: Name, local: Boolean = false) =
when { when {
local -> CallableId(name) local -> CallableId(name)
@@ -145,41 +144,23 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
} }
} }
fun T?.toDelegatedSelfType(firClass: AbstractFirRegularClassBuilder): FirResolvedTypeRef { fun T?.toDelegatedSelfType(firClass: AbstractFirRegularClassBuilder): FirResolvedTypeRef =
toDelegatedSelfType(firClass, firClass.symbol)
fun T?.toDelegatedSelfType(firObject: FirAnonymousObjectBuilder): FirResolvedTypeRef =
toDelegatedSelfType(firObject, firObject.symbol)
private fun T?.toDelegatedSelfType(firClass: FirClassBuilder, symbol: FirClassLikeSymbol<*>): FirResolvedTypeRef {
return buildResolvedTypeRef { return buildResolvedTypeRef {
source = this@toDelegatedSelfType?.toFirSourceElement() source = this@toDelegatedSelfType?.toFirSourceElement()
type = ConeClassLikeTypeImpl( type = ConeClassLikeTypeImpl(
firClass.symbol.toLookupTag(), symbol.toLookupTag(),
firClass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(), firClass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
false false
) )
} }
} }
fun T?.toDelegatedSelfType(firObject: FirAnonymousObjectBuilder): FirResolvedTypeRef {
return buildResolvedTypeRef {
source = this@toDelegatedSelfType?.toFirSourceElement()
type = ConeClassLikeTypeImpl(
firObject.symbol.toLookupTag(),
firObject.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
false
)
}
}
fun typeParametersFromSelfType(
delegatedSelfTypeRef: FirTypeRef
): List<FirTypeParameterRef> {
return delegatedSelfTypeRef.coneTypeSafe<ConeKotlinType>()
?.typeArguments
?.map {
buildConstructedClassTypeParameterRef {
symbol = ((it as ConeTypeParameterType).lookupTag.symbol as FirTypeParameterSymbol)
}
}
?: emptyList()
}
fun constructorTypeParametersFromConstructedClass(ownerTypeParameters: List<FirTypeParameterRef>): List<FirTypeParameterRef> { fun constructorTypeParametersFromConstructedClass(ownerTypeParameters: List<FirTypeParameterRef>): List<FirTypeParameterRef> {
return ownerTypeParameters.mapNotNull { return ownerTypeParameters.mapNotNull {
val declaredTypeParameter = (it as? FirTypeParameter) ?: return@mapNotNull null val declaredTypeParameter = (it as? FirTypeParameter) ?: return@mapNotNull null
@@ -334,14 +334,11 @@ class DeclarationsConverter(
var identifier: String? = null var identifier: String? = null
val firTypeParameters = mutableListOf<FirTypeParameter>() val firTypeParameters = mutableListOf<FirTypeParameter>()
var primaryConstructor: LighterASTNode? = null var primaryConstructor: LighterASTNode? = null
val superTypeRefs = mutableListOf<FirTypeRef>()
val superTypeCallEntry = mutableListOf<FirExpression>()
var delegatedSuperTypeRef: FirTypeRef? = null
val typeConstraints = mutableListOf<TypeConstraint>() val typeConstraints = mutableListOf<TypeConstraint>()
var classBody: LighterASTNode? = null var classBody: LighterASTNode? = null
var superTypeList: LighterASTNode? = null
var typeParameterList: LighterASTNode? = null var typeParameterList: LighterASTNode? = null
var delegatedConstructorSource: FirLightSourceElement? = null
classNode.forEachChildren { classNode.forEachChildren {
when (it.tokenType) { when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it) MODIFIER_LIST -> modifiers = convertModifierList(it)
@@ -351,12 +348,7 @@ class DeclarationsConverter(
IDENTIFIER -> identifier = it.asText IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> typeParameterList = it TYPE_PARAMETER_LIST -> typeParameterList = it
PRIMARY_CONSTRUCTOR -> primaryConstructor = it PRIMARY_CONSTRUCTOR -> primaryConstructor = it
SUPER_TYPE_LIST -> convertDelegationSpecifiers(it).let { SUPER_TYPE_LIST -> superTypeList = it
delegatedSuperTypeRef = it.delegatedSuperTypeRef
superTypeRefs += it.superTypesRef
superTypeCallEntry += it.delegatedConstructorArguments
delegatedConstructorSource = it.delegatedConstructorSource
}
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it) TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
CLASS_BODY -> classBody = it CLASS_BODY -> classBody = it
} }
@@ -375,104 +367,121 @@ class DeclarationsConverter(
val isLocal = isClassLocal(classNode) { getParent() } val isLocal = isClassLocal(classNode) { getParent() }
return withChildClassName(className) { return withChildClassName(className) {
val status = FirDeclarationStatusImpl( withCapturedTypeParameters {
if (isLocal) Visibilities.LOCAL else modifiers.getVisibility(), val status = FirDeclarationStatusImpl(
modifiers.getModality() if (isLocal) Visibilities.LOCAL else modifiers.getVisibility(),
).apply { modifiers.getModality()
isExpect = modifiers.hasExpect() ).apply {
isActual = modifiers.hasActual() isExpect = modifiers.hasExpect()
isInner = modifiers.isInner() isActual = modifiers.hasActual()
isCompanion = modifiers.isCompanion() && classKind == ClassKind.OBJECT isInner = modifiers.isInner()
isData = modifiers.isDataClass() && classKind != ClassKind.OBJECT isCompanion = modifiers.isCompanion() && classKind == ClassKind.OBJECT
isInline = modifiers.hasInline() isData = modifiers.isDataClass() && classKind != ClassKind.OBJECT
} isInline = modifiers.hasInline()
}
val classBuilder = if (status.modality == Modality.SEALED) { val classBuilder = if (status.modality == Modality.SEALED) {
FirSealedClassBuilder() FirSealedClassBuilder()
} else { } else {
FirClassImplBuilder() FirClassImplBuilder()
} }
classBuilder.apply { classBuilder.apply {
source = classNode.toFirSourceElement() source = classNode.toFirSourceElement()
session = baseSession session = baseSession
name = className name = className
this.status = status this.status = status
this.classKind = classKind this.classKind = classKind
scopeProvider = baseScopeProvider scopeProvider = baseScopeProvider
symbol = FirRegularClassSymbol(context.currentClassId) symbol = FirRegularClassSymbol(context.currentClassId)
annotations += modifiers.annotations annotations += modifiers.annotations
typeParameters += firTypeParameters typeParameters += firTypeParameters
val selfType = classNode.toDelegatedSelfType(this) if (!status.isInner) clearCapturedTypeParameters()
typeParameters += context.capturedTypeParameters.map { buildOuterClassTypeParameterRef { symbol = it } }
addCapturedTypeParameters(firTypeParameters)
when { val selfType = classNode.toDelegatedSelfType(this)
modifiers.isEnum() && (classKind == ClassKind.ENUM_CLASS) -> {
delegatedSuperTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl( val delegationSpecifiers = superTypeList?.let { convertDelegationSpecifiers(it) }
implicitEnumType.type.lookupTag, var delegatedSuperTypeRef: FirTypeRef? = delegationSpecifiers?.delegatedSuperTypeRef
arrayOf(selfType.coneTypeUnsafe()), val delegatedConstructorSource: FirLightSourceElement? = delegationSpecifiers?.delegatedConstructorSource
isNullable = false val superTypeCallEntry = delegationSpecifiers?.delegatedConstructorArguments.orEmpty()
) val superTypeRefs = mutableListOf<FirTypeRef>()
delegationSpecifiers?.let { superTypeRefs += it.superTypesRef }
when {
modifiers.isEnum() && (classKind == ClassKind.ENUM_CLASS) -> {
delegatedSuperTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
implicitEnumType.type.lookupTag,
arrayOf(selfType.coneTypeUnsafe()),
isNullable = false
)
}
superTypeRefs += delegatedSuperTypeRef
}
modifiers.isAnnotation() && (classKind == ClassKind.ANNOTATION_CLASS) -> {
superTypeRefs += implicitAnnotationType
} }
superTypeRefs += delegatedSuperTypeRef!!
} }
modifiers.isAnnotation() && (classKind == ClassKind.ANNOTATION_CLASS) -> { val defaultDelegatedSuperTypeRef = implicitAnyType
superTypeRefs += implicitAnnotationType
superTypeRefs.ifEmpty { superTypeRefs += defaultDelegatedSuperTypeRef }
this.superTypeRefs += superTypeRefs
val secondaryConstructors = classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR)
val classWrapper = ClassWrapper(
className, modifiers, classKind, classBuilder,
hasPrimaryConstructor = primaryConstructor != null,
hasSecondaryConstructor = secondaryConstructors.isNotEmpty(),
hasDefaultConstructor = if (primaryConstructor != null) !primaryConstructor!!.hasValueParameters()
else secondaryConstructors.isEmpty() || secondaryConstructors.any { !it.hasValueParameters() },
delegatedSelfTypeRef = selfType,
delegatedSuperTypeRef = delegatedSuperTypeRef ?: defaultDelegatedSuperTypeRef,
superTypeCallEntry = superTypeCallEntry
)
//parse primary constructor
val primaryConstructorWrapper = convertPrimaryConstructor(primaryConstructor, classWrapper, delegatedConstructorSource)
val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor
firPrimaryConstructor?.let { declarations += it }
val properties = mutableListOf<FirProperty>()
if (primaryConstructor != null && firPrimaryConstructor != null) {
//parse properties
properties += primaryConstructorWrapper.valueParameters
.filter { it.hasValOrVar() }
.map { it.toFirProperty(baseSession, callableIdForName(it.firValueParameter.name)) }
addDeclarations(properties)
} }
}
val defaultDelegatedSuperTypeRef = implicitAnyType
superTypeRefs.ifEmpty { superTypeRefs += defaultDelegatedSuperTypeRef } //parse declarations
classBody?.let {
addDeclarations(convertClassBody(it, classWrapper))
}
this.superTypeRefs += superTypeRefs //parse data class
if (modifiers.isDataClass() && firPrimaryConstructor != null) {
val zippedParameters = properties.map { it.source?.lightNode!! to it }
zippedParameters.generateComponentFunctions(
baseSession, this, context.packageFqName, context.className, firPrimaryConstructor
)
zippedParameters.generateCopyFunction(
baseSession, classNode, this, context.packageFqName, context.className, firPrimaryConstructor
)
// TODO: equals, hashCode, toString
}
val secondaryConstructors = classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR) if (modifiers.isEnum()) {
val classWrapper = ClassWrapper( generateValuesFunction(baseSession, context.packageFqName, context.className)
className, modifiers, classKind, classBuilder, generateValueOfFunction(baseSession, context.packageFqName, context.className)
hasPrimaryConstructor = primaryConstructor != null, }
hasSecondaryConstructor = secondaryConstructors.isNotEmpty(), }.build()
hasDefaultConstructor = if (primaryConstructor != null) !primaryConstructor!!.hasValueParameters() }
else secondaryConstructors.isEmpty() || secondaryConstructors.any { !it.hasValueParameters() },
delegatedSelfTypeRef = selfType,
delegatedSuperTypeRef = delegatedSuperTypeRef ?: defaultDelegatedSuperTypeRef, superTypeCallEntry = superTypeCallEntry
)
//parse primary constructor
val primaryConstructorWrapper = convertPrimaryConstructor(primaryConstructor, classWrapper, delegatedConstructorSource)
val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor
firPrimaryConstructor?.let { declarations += it }
val properties = mutableListOf<FirProperty>()
if (primaryConstructor != null && firPrimaryConstructor != null) {
//parse properties
properties += primaryConstructorWrapper.valueParameters
.filter { it.hasValOrVar() }
.map { it.toFirProperty(baseSession, callableIdForName(it.firValueParameter.name)) }
addDeclarations(properties)
}
//parse declarations
classBody?.let {
addDeclarations(convertClassBody(it, classWrapper))
}
//parse data class
if (modifiers.isDataClass() && firPrimaryConstructor != null) {
val zippedParameters = properties.map { it.source?.lightNode!! to it }
zippedParameters.generateComponentFunctions(
baseSession, this, context.packageFqName, context.className, firPrimaryConstructor
)
zippedParameters.generateCopyFunction(
baseSession, classNode, this, context.packageFqName, context.className, firPrimaryConstructor
)
// TODO: equals, hashCode, toString
}
if (modifiers.isEnum()) {
generateValuesFunction(baseSession, context.packageFqName, context.className)
generateValueOfFunction(baseSession, context.packageFqName, context.className)
}
}.build()
} }
} }
@@ -512,6 +521,7 @@ class DeclarationsConverter(
classKind = ClassKind.OBJECT classKind = ClassKind.OBJECT
scopeProvider = baseScopeProvider scopeProvider = baseScopeProvider
symbol = FirAnonymousObjectSymbol() symbol = FirAnonymousObjectSymbol()
typeParameters += context.capturedTypeParameters.map { buildOuterClassTypeParameterRef { symbol = it } }
val delegatedSelfType = objectLiteral.toDelegatedSelfType(this) val delegatedSelfType = objectLiteral.toDelegatedSelfType(this)
annotations += modifiers.annotations annotations += modifiers.annotations
this.superTypeRefs += superTypeRefs this.superTypeRefs += superTypeRefs
@@ -527,7 +537,8 @@ class DeclarationsConverter(
superTypeCallEntry = superTypeCallEntry superTypeCallEntry = superTypeCallEntry
) )
//parse primary constructor //parse primary constructor
convertPrimaryConstructor(primaryConstructor, classWrapper, delegatedConstructorSource)?.let { this.declarations += it.firConstructor } convertPrimaryConstructor(primaryConstructor, classWrapper, delegatedConstructorSource)
?.let { this.declarations += it.firConstructor }
//parse declarations //parse declarations
classBody?.let { classBody?.let {
@@ -677,7 +688,7 @@ class DeclarationsConverter(
this.status = status this.status = status
symbol = FirConstructorSymbol(callableIdForClassConstructor()) symbol = FirConstructorSymbol(callableIdForClassConstructor())
annotations += modifiers.annotations annotations += modifiers.annotations
typeParameters += typeParametersFromSelfType(classWrapper.delegatedSelfTypeRef) typeParameters += constructorTypeParametersFromConstructedClass(classWrapper.classBuilder.typeParameters)
this.valueParameters += valueParameters.map { it.firValueParameter } this.valueParameters += valueParameters.map { it.firValueParameter }
delegatedConstructor = firDelegatedCall delegatedConstructor = firDelegatedCall
}, valueParameters }, valueParameters
@@ -743,7 +754,7 @@ class DeclarationsConverter(
context.firFunctionTargets += target context.firFunctionTargets += target
annotations += modifiers.annotations annotations += modifiers.annotations
typeParameters += typeParametersFromSelfType(delegatedSelfTypeRef) typeParameters += constructorTypeParametersFromConstructedClass(classWrapper.classBuilder.typeParameters)
valueParameters += firValueParameters.map { it.firValueParameter } valueParameters += firValueParameters.map { it.firValueParameter }
body = convertFunctionBody(block, null) body = convertFunctionBody(block, null)
context.firFunctionTargets.removeLast() context.firFunctionTargets.removeLast()
@@ -833,8 +844,7 @@ class DeclarationsConverter(
var receiverType: FirTypeRef? = null var receiverType: FirTypeRef? = null
var returnType: FirTypeRef = implicitType var returnType: FirTypeRef = implicitType
val typeConstraints = mutableListOf<TypeConstraint>() val typeConstraints = mutableListOf<TypeConstraint>()
var getter: FirPropertyAccessor? = null val accessors = mutableListOf<LighterASTNode>()
var setter: FirPropertyAccessor? = null
var propertyInitializer: FirExpression? = null var propertyInitializer: FirExpression? = null
var typeParameterList: LighterASTNode? = null var typeParameterList: LighterASTNode? = null
property.forEachChildren { property.forEachChildren {
@@ -848,8 +858,7 @@ class DeclarationsConverter(
PROPERTY_DELEGATE -> delegateExpression = it PROPERTY_DELEGATE -> delegateExpression = it
VAR_KEYWORD -> isVar = true VAR_KEYWORD -> isVar = true
PROPERTY_ACCESSOR -> { PROPERTY_ACCESSOR -> {
val propertyAccessor = convertGetterOrSetter(it, returnType) accessors += it
if (propertyAccessor.isGetter) getter = propertyAccessor else setter = propertyAccessor
} }
else -> if (it.isExpression()) propertyInitializer = expressionConverter.getAsFirExpression(it, "Should have initializer") else -> if (it.isExpression()) propertyInitializer = expressionConverter.getAsFirExpression(it, "Should have initializer")
} }
@@ -899,35 +908,47 @@ class DeclarationsConverter(
this.isLocal = false this.isLocal = false
receiverTypeRef = receiverType receiverTypeRef = receiverType
symbol = FirPropertySymbol(callableIdForName(propertyName)) symbol = FirPropertySymbol(callableIdForName(propertyName))
val delegateBuilder = delegateExpression?.let { withCapturedTypeParameters {
FirWrappedDelegateExpressionBuilder().apply { typeParameters += firTypeParameters
source = it.toFirSourceElement() addCapturedTypeParameters(firTypeParameters)
expression = expressionConverter.getAsFirExpression(it, "Should have delegate")
val delegateBuilder = delegateExpression?.let {
FirWrappedDelegateExpressionBuilder().apply {
source = it.toFirSourceElement()
expression = expressionConverter.getAsFirExpression(it, "Should have delegate")
}
} }
}
status = FirDeclarationStatusImpl(modifiers.getVisibility(), modifiers.getModality()).apply { status = FirDeclarationStatusImpl(modifiers.getVisibility(), modifiers.getModality()).apply {
isExpect = modifiers.hasExpect() isExpect = modifiers.hasExpect()
isActual = modifiers.hasActual() isActual = modifiers.hasActual()
isOverride = modifiers.hasOverride() isOverride = modifiers.hasOverride()
isConst = modifiers.isConst() isConst = modifiers.isConst()
isLateInit = modifiers.hasLateinit() isLateInit = modifiers.hasLateinit()
} }
typeParameters += firTypeParameters
this.getter = getter ?: FirDefaultPropertyGetter(null, session, returnType, modifiers.getVisibility())
this.setter = if (isVar) setter ?: FirDefaultPropertySetter(null, session, returnType, modifiers.getVisibility()) else null
val receiver = delegateExpression?.let {
expressionConverter.getAsFirExpression<FirExpression>(it, "Should have delegate") val convertedAccessors = accessors.map { convertGetterOrSetter(it, returnType) }
this.getter = convertedAccessors.find { it.isGetter }
?: FirDefaultPropertyGetter(null, session, returnType, modifiers.getVisibility())
this.setter =
if (isVar) {
convertedAccessors.find { it.isSetter }
?: FirDefaultPropertySetter(null, session, returnType, modifiers.getVisibility())
} else null
val receiver = delegateExpression?.let {
expressionConverter.getAsFirExpression<FirExpression>(it, "Should have delegate")
}
generateAccessorsByDelegate(
delegateBuilder,
classWrapper?.classBuilder,
baseSession,
isExtension = receiverType != null,
stubMode,
receiver
)
} }
generateAccessorsByDelegate(
delegateBuilder,
classWrapper?.classBuilder,
baseSession,
isExtension = receiverType != null,
stubMode,
receiver
)
} }
annotations += modifiers.annotations annotations += modifiers.annotations
} }
@@ -1150,12 +1171,14 @@ class DeclarationsConverter(
context.firFunctionTargets += target context.firFunctionTargets += target
annotations += modifiers.annotations annotations += modifiers.annotations
if (this is FirSimpleFunctionBuilder) { withCapturedTypeParameters {
typeParameters += firTypeParameters if (this is FirSimpleFunctionBuilder) {
typeParameters += firTypeParameters
addCapturedTypeParameters(typeParameters)
}
valueParametersList?.let { list -> valueParameters += convertValueParameters(list).map { it.firValueParameter } }
body = convertFunctionBody(block, expression)
} }
valueParametersList?.let { list -> valueParameters += convertValueParameters(list).map { it.firValueParameter } }
body = convertFunctionBody(block, expression)
context.firFunctionTargets.removeLast() context.firFunctionTargets.removeLast()
}.build().also { }.build().also {
target.bind(it) target.bind(it)
@@ -27,7 +27,7 @@ class ClassWrapper(
val hasDefaultConstructor: Boolean, val hasDefaultConstructor: Boolean,
val delegatedSelfTypeRef: FirTypeRef, val delegatedSelfTypeRef: FirTypeRef,
val delegatedSuperTypeRef: FirTypeRef, val delegatedSuperTypeRef: FirTypeRef,
val superTypeCallEntry: MutableList<FirExpression>, val superTypeCallEntry: List<FirExpression>,
) { ) {
fun isObjectLiteral(): Boolean { fun isObjectLiteral(): Boolean {
return className == SpecialNames.NO_NAME_PROVIDED && isObject() return className == SpecialNames.NO_NAME_PROVIDED && isObject()