use of org.eclipse.ceylon.langtools.tools.javac.code.Symbol in project ceylon by eclipse.
the class Attr method visitReference.
@Override
public void visitReference(final JCMemberReference that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
if (pt().hasTag(NONE)) {
// method reference only allowed in assignment or method invocation/cast context
log.error(that.pos(), "unexpected.mref");
}
result = that.type = types.createErrorType(pt());
return;
}
final Env<AttrContext> localEnv = env.dup(that);
try {
// attribute member reference qualifier - if this is a constructor
// reference, the expected kind must be a type
Type exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that));
if (that.getMode() == JCMemberReference.ReferenceMode.NEW) {
exprType = chk.checkConstructorRefType(that.expr, exprType);
if (!exprType.isErroneous() && exprType.isRaw() && that.typeargs != null) {
log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()), diags.fragment("mref.infer.and.explicit.params"));
exprType = types.createErrorType(exprType);
}
}
if (exprType.isErroneous()) {
// if the qualifier expression contains problems,
// give up attribution of method reference
result = that.type = exprType;
return;
}
if (TreeInfo.isStaticSelector(that.expr, names)) {
// if the qualifier is a type, validate it; raw warning check is
// omitted as we don't know at this stage as to whether this is a
// raw selector (because of inference)
chk.validate(that.expr, env, false);
}
// attrib type-arguments
List<Type> typeargtypes = List.nil();
if (that.typeargs != null) {
typeargtypes = attribTypes(that.typeargs, localEnv);
}
Type desc;
Type currentTarget = pt();
boolean isTargetSerializable = resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK && isSerializable(currentTarget);
if (currentTarget != Type.recoveryType) {
currentTarget = types.removeWildcards(targetChecker.visit(currentTarget, that));
desc = types.findDescriptorType(currentTarget);
} else {
currentTarget = Type.recoveryType;
desc = fallbackDescriptorType(that);
}
setFunctionalInfo(localEnv, that, pt(), desc, currentTarget, resultInfo.checkContext);
List<Type> argtypes = desc.getParameterTypes();
Resolve.MethodCheck referenceCheck = rs.resolveMethodCheck;
if (resultInfo.checkContext.inferenceContext().free(argtypes)) {
referenceCheck = rs.new MethodReferenceCheck(resultInfo.checkContext.inferenceContext());
}
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult = null;
List<Type> saved_undet = resultInfo.checkContext.inferenceContext().save();
try {
refResult = rs.resolveMemberReference(localEnv, that, that.expr.type, that.name, argtypes, typeargtypes, referenceCheck, resultInfo.checkContext.inferenceContext(), resultInfo.checkContext.deferredAttrContext().mode);
} finally {
resultInfo.checkContext.inferenceContext().rollback(saved_undet);
}
Symbol refSym = refResult.fst;
Resolve.ReferenceLookupHelper lookupHelper = refResult.snd;
if (refSym.kind != MTH) {
boolean targetError;
switch(refSym.kind) {
case ABSENT_MTH:
targetError = false;
break;
case WRONG_MTH:
case WRONG_MTHS:
case AMBIGUOUS:
case HIDDEN:
case STATICERR:
case MISSING_ENCL:
case WRONG_STATICNESS:
targetError = true;
break;
default:
Assert.error("unexpected result kind " + refSym.kind);
targetError = false;
}
JCDiagnostic detailsDiag = ((Resolve.ResolveError) refSym.baseSymbol()).getDiagnostic(JCDiagnostic.DiagnosticType.FRAGMENT, that, exprType.tsym, exprType, that.name, argtypes, typeargtypes);
JCDiagnostic.DiagnosticType diagKind = targetError ? JCDiagnostic.DiagnosticType.FRAGMENT : JCDiagnostic.DiagnosticType.ERROR;
JCDiagnostic diag = diags.create(diagKind, log.currentSource(), that, "invalid.mref", Kinds.kindName(that.getMode()), detailsDiag);
if (targetError && currentTarget == Type.recoveryType) {
// a target error doesn't make sense during recovery stage
// as we don't know what actual parameter types are
result = that.type = currentTarget;
return;
} else {
if (targetError) {
resultInfo.checkContext.report(that, diag);
} else {
log.report(diag);
}
result = that.type = types.createErrorType(currentTarget);
return;
}
}
that.sym = refSym.baseSymbol();
that.kind = lookupHelper.referenceKind(that.sym);
that.ownerAccessible = rs.isAccessible(localEnv, that.sym.enclClass());
if (desc.getReturnType() == Type.recoveryType) {
// stop here
result = that.type = currentTarget;
return;
}
if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
if (that.getMode() == ReferenceMode.INVOKE && TreeInfo.isStaticSelector(that.expr, names) && that.kind.isUnbound() && !desc.getParameterTypes().head.isParameterized()) {
chk.checkRaw(that.expr, localEnv);
}
if (that.sym.isStatic() && TreeInfo.isStaticSelector(that.expr, names) && exprType.getTypeArguments().nonEmpty()) {
// static ref with class type-args
log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()), diags.fragment("static.mref.with.targs"));
result = that.type = types.createErrorType(currentTarget);
return;
}
if (that.sym.isStatic() && !TreeInfo.isStaticSelector(that.expr, names) && !that.kind.isUnbound()) {
// no static bound mrefs
log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()), diags.fragment("static.bound.mref"));
result = that.type = types.createErrorType(currentTarget);
return;
}
if (!refSym.isStatic() && that.kind == JCMemberReference.ReferenceKind.SUPER) {
// Check that super-qualified symbols are not abstract (JLS)
rs.checkNonAbstract(that.pos(), that.sym);
}
if (isTargetSerializable) {
chk.checkElemAccessFromSerializableLambda(that);
}
}
ResultInfo checkInfo = resultInfo.dup(newMethodTemplate(desc.getReturnType().hasTag(VOID) ? Type.noType : desc.getReturnType(), that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes), new FunctionalReturnContext(resultInfo.checkContext));
Type refType = checkId(noCheckTree, lookupHelper.site, refSym, localEnv, checkInfo);
if (that.kind.isUnbound() && resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
// re-generate inference constraints for unbound receiver
if (!types.isSubtype(resultInfo.checkContext.inferenceContext().asUndetVar(argtypes.head), exprType)) {
// cannot happen as this has already been checked - we just need
// to regenerate the inference constraints, as that has been lost
// as a result of the call to inferenceContext.save()
Assert.error("Can't get here");
}
}
if (!refType.isErroneous()) {
refType = types.createMethodTypeWithReturn(refType, adjustMethodReturnType(lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
}
// go ahead with standard method reference compatibility check - note that param check
// is a no-op (as this has been taken care during method applicability)
boolean isSpeculativeRound = resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
// avoids recovery at this stage
that.type = currentTarget;
checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
if (!isSpeculativeRound) {
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget);
}
result = check(that, currentTarget, VAL, resultInfo);
} catch (Types.FunctionDescriptorLookupError ex) {
JCDiagnostic cause = ex.getDiagnostic();
resultInfo.checkContext.report(that, cause);
result = that.type = types.createErrorType(pt());
return;
}
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Symbol in project ceylon by eclipse.
the class Attr method selectSym.
/*
// Added by Ceylon
private Symbol resolveIndyCall(JCTree tree,
JCExpression indyReturnTypeExpression, List<JCExpression> indyParameterTypeExpressions,
Name indyName,
JCExpression bsmType, Name bsmName, List<Object> bsmStatic,
List<Type> parameterTypes){
// build the list of static bsm arguments
List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
syms.stringType,
syms.methodTypeType).appendList(bsmStaticArgToTypes(bsmStatic));
// find the type of the bootstrap method class
Type bsmSite = attribTree(bsmType, env, TYP, Infer.anyPoly);
// find the bsm method
Symbol bsm = rs.resolveInternalMethod(tree.pos(), env, bsmSite,
bsmName, bsm_staticArgs, List.<Type>nil());
if(!bsm.isStatic())
log.error(tree.pos(), "ceylon", "Bootstrap method must be static: " + bsmName.toString());
// find the type of the indy call
Type indyReturnType = attribTree(indyReturnTypeExpression, env, TYP, Infer.anyPoly);
ListBuffer<Type> indyParameterTypes = new ListBuffer<Type>();
int c=0;
List<Type> givenParameterTypes = parameterTypes;
for(JCExpression expectedParamTypeExpr : indyParameterTypeExpressions){
// also check that the parameter types we are passing to the method are compatible with the declared type
Type givenParameterType = givenParameterTypes.head;
if(givenParameterType == null) {
log.error(tree.pos(), "ceylon", "Indy declared method expects more parameters than given. Expecting " + indyParameterTypeExpressions.size()
+ ", but given " + c);
return syms.errSymbol;
}
Type paramType = attribTree(expectedParamTypeExpr, env, TYP, Infer.anyPoly);
if(!types.isAssignable(givenParameterType, paramType)) {
log.error(tree.pos(), "ceylon", "Indy given method parameter "+c+" not compatible with expected parameter type: " + paramType
+ ", but given " + givenParameterType);
return syms.errSymbol;
}
indyParameterTypes.append(paramType);
c++;
givenParameterTypes = givenParameterTypes.tail;
}
if(!givenParameterTypes.isEmpty()) {
log.error(tree.pos(), "ceylon", "Indy declared method expects less parameters than given. Expecting " + indyParameterTypeExpressions.size()
+ ", but given " + parameterTypes.size());
return syms.errSymbol;
}
MethodType indyType = new MethodType(indyParameterTypes.toList(), indyReturnType, List.<Type>nil(), syms.methodClass);
// make an indy symbol for it
DynamicMethodSymbol dynSym =
new DynamicMethodSymbol(indyName,
syms.noSymbol,
bsm.isStatic() ?
ClassFile.REF_invokeStatic :
ClassFile.REF_invokeVirtual,
(MethodSymbol)bsm,
indyType,
bsmStatic.toArray());
return dynSym;
}
*/
// where
/**
* Determine symbol referenced by a Select expression,
*
* @param tree The select tree.
* @param site The type of the selected expression,
* @param env The current environment.
* @param resultInfo The current result.
*/
private Symbol selectSym(JCFieldAccess tree, Symbol location, Type site, Env<AttrContext> env, ResultInfo resultInfo) {
DiagnosticPosition pos = tree.pos();
Name name = tree.name;
switch(site.getTag()) {
case PACKAGE:
return rs.accessBase(rs.findIdentInPackage(env, site.tsym, name, resultInfo.pkind), pos, location, site, name, true);
case ARRAY:
case CLASS:
if (resultInfo.pt.hasTag(METHOD) || resultInfo.pt.hasTag(FORALL)) {
return rs.resolveQualifiedMethod(pos, env, location, site, name, resultInfo.pt.getParameterTypes(), resultInfo.pt.getTypeArguments());
} else if (name == names._this || name == names._super) {
return rs.resolveSelf(pos, env, site.tsym, name);
} else if (name == names._class) {
// In this case, we have already made sure in
// visitSelect that qualifier expression is a type.
Type t = syms.classType;
List<Type> typeargs = allowGenerics ? List.of(types.erasure(site)) : List.<Type>nil();
t = new ClassType(t.getEnclosingType(), typeargs, t.tsym);
return new VarSymbol(STATIC | PUBLIC | FINAL, names._class, t, site.tsym);
} else {
// We are seeing a plain identifier as selector.
Symbol sym = rs.findIdentInType(env, site, name, resultInfo.pkind);
if ((resultInfo.pkind & Kinds.ERRONEOUS) == 0)
sym = rs.accessBase(sym, pos, location, site, name, true);
return sym;
}
case WILDCARD:
throw new AssertionError(tree);
case TYPEVAR:
// Normally, site.getUpperBound() shouldn't be null.
// It should only happen during memberEnter/attribBase
// when determining the super type which *must* beac
// done before attributing the type variables. In
// other words, we are seeing this illegal program:
// class B<T> extends A<T.foo> {}
Symbol sym = (site.getUpperBound() != null) ? selectSym(tree, location, capture(site.getUpperBound()), env, resultInfo) : null;
if (sym == null) {
log.error(pos, "type.var.cant.be.deref");
return syms.errSymbol;
} else {
// Ceylon: relax the rules for private methods in wildcards, damnit, we want the private
// method to be called, not any subtype's method we can't possibly know about, this is really
// a lame Java decision.
Symbol sym2 = (!sourceLanguage.isCeylon() && (sym.flags() & Flags.PRIVATE) != 0) ? rs.new AccessError(env, site, sym) : sym;
rs.accessBase(sym2, pos, location, site, name, true);
return sym;
}
case ERROR:
// preserve identifier names through errors
return types.createErrorType(name, site.tsym, site).tsym;
default:
// .class is allowed for these.
if (name == names._class) {
// In this case, we have already made sure in Select that
// qualifier expression is a type.
Type t = syms.classType;
Type arg = types.boxedClass(site).type;
t = new ClassType(t.getEnclosingType(), List.of(arg), t.tsym);
return new VarSymbol(STATIC | PUBLIC | FINAL, names._class, t, site.tsym);
} else {
log.error(pos, "cant.deref", site);
return syms.errSymbol;
}
}
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Symbol in project ceylon by eclipse.
the class Attr method visitBinary.
public void visitBinary(JCBinary tree) {
// Attribute arguments.
Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env));
Type right = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.rhs, env));
// Find operator.
Symbol operator = tree.operator = rs.resolveBinaryOperator(tree.pos(), tree.getTag(), env, left, right);
Type owntype = types.createErrorType(tree.type);
if (operator.kind == MTH && !left.isErroneous() && !right.isErroneous()) {
owntype = operator.type.getReturnType();
// This will figure out when unboxing can happen and
// choose the right comparison operator.
int opc = chk.checkOperator(tree.lhs.pos(), (OperatorSymbol) operator, tree.getTag(), left, right);
// If both arguments are constants, fold them.
if (left.constValue() != null && right.constValue() != null) {
Type ctype = cfolder.fold2(opc, left, right);
if (ctype != null) {
owntype = cfolder.coerce(ctype, owntype);
}
}
// comparisons will not have an acmp* opc at this point.
if ((opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne)) {
if (!types.isEqualityComparable(left, right, new Warner(tree.pos()))) {
log.error(tree.pos(), "incomparable.types", left, right);
}
}
chk.checkDivZero(tree.rhs.pos(), operator, right);
}
result = check(tree, owntype, VAL, resultInfo);
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Symbol in project ceylon by eclipse.
the class Attr method visitApply.
/**
* Visitor method for method invocations.
* NOTE: The method part of an application will have in its type field
* the return type of the method, not the method's type itself!
*/
public void visitApply(JCMethodInvocation tree) {
// The local environment of a method application is
// a new environment nested in the current one.
Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
// The types of the actual method arguments.
List<Type> argtypes;
// The types of the actual method type arguments.
List<Type> typeargtypes = null;
Name methName = TreeInfo.name(tree.meth);
boolean isConstructorCall = methName == names._this || methName == names._super;
ListBuffer<Type> argtypesBuf = new ListBuffer<>();
if (isConstructorCall) {
// Check that this is the first statement in a constructor.
if (checkFirstConstructorStat(tree, env)) {
// Record the fact
// that this is a constructor call (using isSelfCall).
localEnv.info.isSelfCall = true;
// Attribute arguments, yielding list of argument types.
int kind = attribArgs(MTH, tree.args, localEnv, argtypesBuf);
argtypes = argtypesBuf.toList();
typeargtypes = attribTypes(tree.typeargs, localEnv);
// Variable `site' points to the class in which the called
// constructor is defined.
Type site = env.enclClass.sym.type;
if (methName == names._super) {
if (site == syms.objectType) {
log.error(tree.meth.pos(), "no.superclass", site);
site = types.createErrorType(syms.objectType);
} else {
site = types.supertype(site);
}
}
if (site.hasTag(CLASS)) {
Type encl = site.getEnclosingType();
while (encl != null && encl.hasTag(TYPEVAR)) encl = encl.getUpperBound();
if (encl.hasTag(CLASS)) {
if (tree.meth.hasTag(SELECT)) {
JCTree qualifier = ((JCFieldAccess) tree.meth).selected;
// We are seeing a prefixed call, of the form
// <expr>.super(...).
// Check that the prefix expression conforms
// to the outer instance type of the class.
chk.checkRefType(qualifier.pos(), attribExpr(qualifier, localEnv, encl));
} else if (methName == names._super) {
// qualifier omitted; check for existence
// of an appropriate implicit qualifier.
rs.resolveImplicitThis(tree.meth.pos(), localEnv, site, true);
}
} else if (tree.meth.hasTag(SELECT)) {
log.error(tree.meth.pos(), "illegal.qual.not.icls", site.tsym);
}
// prefix the implicit String and int parameters
if (site.tsym == syms.enumSym && allowEnums)
argtypes = argtypes.prepend(syms.intType).prepend(syms.stringType);
// Resolve the called constructor under the assumption
// that we are referring to a superclass instance of the
// current instance (JLS ???).
boolean selectSuperPrev = localEnv.info.selectSuper;
localEnv.info.selectSuper = true;
localEnv.info.pendingResolutionPhase = null;
Symbol sym = rs.resolveConstructor(tree.meth.pos(), localEnv, site, argtypes, typeargtypes);
localEnv.info.selectSuper = selectSuperPrev;
// Set method symbol to resolved constructor...
TreeInfo.setSymbol(tree.meth, sym);
// ...and check that it is legal in the current context.
// (this will also set the tree's type)
Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
checkId(tree.meth, site, sym, localEnv, new ResultInfo(kind, mpt));
}
// Otherwise, `site' is an error type and we do nothing
}
result = tree.type = syms.voidType;
} else {
// Otherwise, we are seeing a regular method call.
// Attribute the arguments, yielding list of argument types, ...
int kind = attribArgs(VAL, tree.args, localEnv, argtypesBuf);
argtypes = argtypesBuf.toList();
typeargtypes = attribAnyTypes(tree.typeargs, localEnv);
// ... and attribute the method using as a prototype a methodtype
// whose formal argument types is exactly the list of actual
// arguments (this will also set the method symbol).
Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
localEnv.info.pendingResolutionPhase = null;
Type mtype = attribTree(tree.meth, localEnv, new ResultInfo(kind, mpt, resultInfo.checkContext));
// Compute the result type.
Type restype = mtype.getReturnType();
if (restype.hasTag(TypeTag.WILDCARD))
throw new AssertionError(mtype);
Type qualifier = (tree.meth.hasTag(SELECT)) ? ((JCFieldAccess) tree.meth).selected.type : env.enclClass.sym.type;
restype = adjustMethodReturnType(qualifier, methName, argtypes, restype);
chk.checkRefTypes(tree.typeargs, typeargtypes);
// Check that value of resulting type is admissible in the
// current context. Also, capture the return type
result = check(tree, capture(restype), VAL, resultInfo);
}
chk.validate(tree.typeargs, localEnv);
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Symbol in project ceylon by eclipse.
the class Attr method lambdaEnv.
/* This method returns an environment to be used to attribute a lambda
* expression.
*
* The owner of this environment is a method symbol. If the current owner
* is not a method, for example if the lambda is used to initialize
* a field, then if the field is:
*
* - an instance field, we use the first constructor.
* - a static field, we create a fake clinit method.
*/
public Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) {
Env<AttrContext> lambdaEnv;
Symbol owner = env.info.scope.owner;
if (owner.kind == VAR && owner.owner.kind == TYP) {
// field initializer
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dupUnshared()));
ClassSymbol enclClass = owner.enclClass();
/* if the field isn't static, then we can get the first constructor
* and use it as the owner of the environment. This is what
* LTM code is doing to look for type annotations so we are fine.
*/
if ((owner.flags() & STATIC) == 0) {
for (Symbol s : enclClass.members_field.getElementsByName(names.init)) {
lambdaEnv.info.scope.owner = s;
break;
}
} else {
/* if the field is static then we need to create a fake clinit
* method, this method can later be reused by LTM.
*/
MethodSymbol clinit = clinits.get(enclClass);
if (clinit == null) {
Type clinitType = new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass);
clinit = new MethodSymbol(STATIC | SYNTHETIC | PRIVATE, names.clinit, clinitType, enclClass);
clinit.params = List.<VarSymbol>nil();
clinits.put(enclClass, clinit);
}
lambdaEnv.info.scope.owner = clinit;
}
} else {
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
}
return lambdaEnv;
}
Aggregations