diff --git a/java/src/com/google/template/soy/jbcsrc/ExternCompiler.java b/java/src/com/google/template/soy/jbcsrc/ExternCompiler.java index 8e1fdafe60..2d25b88dc8 100644 --- a/java/src/com/google/template/soy/jbcsrc/ExternCompiler.java +++ b/java/src/com/google/template/soy/jbcsrc/ExternCompiler.java @@ -572,7 +572,7 @@ private static Expression adaptImplicitParameter(ConstantVariables vars, TypeInf } private SoyExpression adaptReturnExpression(SoyExpression raw, SoyRuntimeType type) { - return raw.coerceTo(type.runtimeType()); + return raw.coerceTo(type); } /** diff --git a/java/src/com/google/template/soy/jbcsrc/SoyNodeCompiler.java b/java/src/com/google/template/soy/jbcsrc/SoyNodeCompiler.java index bdb8068a05..6e738f9966 100644 --- a/java/src/com/google/template/soy/jbcsrc/SoyNodeCompiler.java +++ b/java/src/com/google/template/soy/jbcsrc/SoyNodeCompiler.java @@ -2149,7 +2149,7 @@ protected Statement visitAssignmentNode(AssignmentNode node) { // ASM has no common type for object v. primitive representations. So we need to coerce the // new value to fix within the bounds of the old value. This is mostly boxed v. unboxed and // numeric conversions among primitives. - newValue = newValue.coerceTo(letOrParam.accessor().resultType()); + newValue = newValue.coerceToTypeOf(letOrParam.accessor()); if (letOrParam instanceof Variable) { // This is assignment on a let. diff --git a/java/src/com/google/template/soy/jbcsrc/restricted/SoyExpression.java b/java/src/com/google/template/soy/jbcsrc/restricted/SoyExpression.java index c072e50ac2..c55a37cfc3 100644 --- a/java/src/com/google/template/soy/jbcsrc/restricted/SoyExpression.java +++ b/java/src/com/google/template/soy/jbcsrc/restricted/SoyExpression.java @@ -1026,7 +1026,7 @@ public SoyExpression coerceTo(Type runtimeType) { // Field may be a subclass of SoyValue, so need to perform a cast. return SoyExpression.forSoyValue( boxed.soyType(), boxed.delegate.checkedCast(runtimeType)); - } else if (BytecodeUtils.STRING_TYPE.equals(runtimeType)) { + } else if (runtimeType.equals(BytecodeUtils.STRING_TYPE)) { return this.unboxAsStringOrJavaNull(); } // Unhandled cases where we have a boxed value (list, message) but require an @@ -1034,4 +1034,26 @@ public SoyExpression coerceTo(Type runtimeType) { } return this; } + + public SoyExpression coerceTo(SoyRuntimeType soyRuntimeType) { + if (soyRuntimeType.runtimeType().equals(BytecodeUtils.LIST_TYPE)) { + Expression unboxed = unboxAsListOrJavaNull(); + return (unboxed instanceof SoyExpression) + ? (SoyExpression) unboxed + : SoyExpression.forList(soyRuntimeType.asListType(), unboxed); + } else if (!soyRuntimeType.isBoxed() && soyRuntimeType.isKnownProtoOrUnionOfProtos()) { + Expression unboxed = unboxAsMessageOrJavaNull(soyRuntimeType.runtimeType()); + return (unboxed instanceof SoyExpression) + ? (SoyExpression) unboxed + : SoyExpression.forProto(soyRuntimeType, unboxed); + } + return coerceTo(soyRuntimeType.runtimeType()); + } + + public SoyExpression coerceToTypeOf(Expression expression) { + if (expression instanceof SoyExpression) { + return coerceTo(((SoyExpression) expression).soyRuntimeType()); + } + return coerceTo(expression.resultType()); + } } diff --git a/java/src/com/google/template/soy/jssrc/internal/GenJsCodeVisitor.java b/java/src/com/google/template/soy/jssrc/internal/GenJsCodeVisitor.java index 2d32fc7129..898eb8a585 100644 --- a/java/src/com/google/template/soy/jssrc/internal/GenJsCodeVisitor.java +++ b/java/src/com/google/template/soy/jssrc/internal/GenJsCodeVisitor.java @@ -1631,10 +1631,12 @@ protected void visitExternNode(ExternNode node) { JsDoc.Builder jsDocBuilder = JsDoc.builder(); for (FunctionType.Parameter param : node.getType().getParameters()) { JsType jsType = getJsTypeForParamForDeclaration(param.getType()); - jsDocBuilder.addParam("p$" + param.getName(), jsType.typeExpr()); + jsDocBuilder.addParam("p$" + param.getName(), jsType.typeExpr()).addGoogRequires(jsType); } - jsDocBuilder.addParameterizedAnnotation( - "return", getJsTypeForParamForDeclaration(node.getType().getReturnType()).typeExpr()); + JsType returnType = getJsTypeForParamForDeclaration(node.getType().getReturnType()); + jsDocBuilder + .addParameterizedAnnotation("return", returnType.typeExpr()) + .addGoogRequires(returnType); Statement body = generateAutoExtern(auto); Expression function = Expressions.function(jsDocBuilder.build(), body);