1 /*
2  * Copyright 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.binder;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableMap;
21 import com.google.turbine.binder.bound.SourceTypeBoundClass;
22 import com.google.turbine.binder.bound.TypeBoundClass;
23 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
24 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
25 import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
26 import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
27 import com.google.turbine.binder.env.Env;
28 import com.google.turbine.binder.sym.ClassSymbol;
29 import com.google.turbine.binder.sym.TyVarSymbol;
30 import com.google.turbine.diag.SourceFile;
31 import com.google.turbine.type.Type;
32 import com.google.turbine.type.Type.ClassTy;
33 import com.google.turbine.type.Type.IntersectionTy;
34 import com.google.turbine.type.Type.TyKind;
35 import com.google.turbine.types.Canonicalize;
36 import java.util.Map;
37 
38 /**
39  * Canonicalizes all qualified types in a {@link SourceTypeBoundClass} using {@link Canonicalize}.
40  */
41 public class CanonicalTypeBinder {
42 
bind( ClassSymbol sym, SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env)43   static SourceTypeBoundClass bind(
44       ClassSymbol sym, SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) {
45     ClassTy superClassType = null;
46     if (base.superClassType() != null && base.superClassType().tyKind() == TyKind.CLASS_TY) {
47       superClassType =
48           Canonicalize.canonicalizeClassTy(
49               base.source(),
50               base.decl().position(),
51               env,
52               base.owner(),
53               (ClassTy) base.superClassType());
54     }
55     ImmutableList.Builder<Type> interfaceTypes = ImmutableList.builder();
56     for (Type i : base.interfaceTypes()) {
57       if (i.tyKind() == TyKind.CLASS_TY) {
58         i =
59             Canonicalize.canonicalizeClassTy(
60                 base.source(), base.decl().position(), env, base.owner(), (ClassTy) i);
61       }
62       interfaceTypes.add(i);
63     }
64     ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
65         typeParameters(base.source(), base.decl().position(), env, sym, base.typeParameterTypes());
66     ImmutableList<MethodInfo> methods =
67         methods(base.source(), base.decl().position(), env, sym, base.methods());
68     ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields());
69     return new SourceTypeBoundClass(
70         interfaceTypes.build(),
71         superClassType,
72         typParamTypes,
73         base.access(),
74         methods,
75         fields,
76         base.owner(),
77         base.kind(),
78         base.children(),
79         base.typeParameters(),
80         base.enclosingScope(),
81         base.scope(),
82         base.memberImports(),
83         base.annotationMetadata(),
84         base.annotations(),
85         base.source(),
86         base.decl());
87   }
88 
fields( SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<FieldInfo> fields)89   private static ImmutableList<FieldInfo> fields(
90       SourceFile source,
91       Env<ClassSymbol, TypeBoundClass> env,
92       ClassSymbol sym,
93       ImmutableList<FieldInfo> fields) {
94     ImmutableList.Builder<FieldInfo> result = ImmutableList.builder();
95     for (FieldInfo base : fields) {
96       result.add(
97           new FieldInfo(
98               base.sym(),
99               Canonicalize.canonicalize(source, base.decl().position(), env, sym, base.type()),
100               base.access(),
101               base.annotations(),
102               base.decl(),
103               base.value()));
104     }
105     return result.build();
106   }
107 
methods( SourceFile source, int position, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<MethodInfo> methods)108   private static ImmutableList<MethodInfo> methods(
109       SourceFile source,
110       int position,
111       Env<ClassSymbol, TypeBoundClass> env,
112       ClassSymbol sym,
113       ImmutableList<MethodInfo> methods) {
114     ImmutableList.Builder<MethodInfo> result = ImmutableList.builder();
115     for (MethodInfo base : methods) {
116       int pos = base.decl() != null ? base.decl().position() : position;
117       ImmutableMap<TyVarSymbol, TyVarInfo> tps =
118           typeParameters(source, pos, env, sym, base.tyParams());
119       Type ret = Canonicalize.canonicalize(source, pos, env, sym, base.returnType());
120       ImmutableList.Builder<ParamInfo> parameters = ImmutableList.builder();
121       for (ParamInfo parameter : base.parameters()) {
122         parameters.add(param(source, pos, env, sym, parameter));
123       }
124       ImmutableList<Type> exceptions = canonicalizeList(source, pos, env, sym, base.exceptions());
125       result.add(
126           new MethodInfo(
127               base.sym(),
128               tps,
129               ret,
130               parameters.build(),
131               exceptions,
132               base.access(),
133               base.defaultValue(),
134               base.decl(),
135               base.annotations(),
136               base.receiver() != null
137                   ? param(source, base.decl().position(), env, sym, base.receiver())
138                   : null));
139     }
140     return result.build();
141   }
142 
param( SourceFile source, int position, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base)143   private static ParamInfo param(
144       SourceFile source,
145       int position,
146       Env<ClassSymbol, TypeBoundClass> env,
147       ClassSymbol sym,
148       ParamInfo base) {
149     return new ParamInfo(
150         Canonicalize.canonicalize(source, position, env, sym, base.type()),
151         base.name(),
152         base.annotations(),
153         base.access());
154   }
155 
typeParameters( SourceFile source, int position, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Map<TyVarSymbol, TyVarInfo> tps)156   private static ImmutableMap<TyVarSymbol, TyVarInfo> typeParameters(
157       SourceFile source,
158       int position,
159       Env<ClassSymbol, TypeBoundClass> env,
160       ClassSymbol sym,
161       Map<TyVarSymbol, TyVarInfo> tps) {
162     ImmutableMap.Builder<TyVarSymbol, TyVarInfo> result = ImmutableMap.builder();
163     for (Map.Entry<TyVarSymbol, TyVarInfo> e : tps.entrySet()) {
164       TyVarInfo info = e.getValue();
165       Type bound = Canonicalize.canonicalize(source, position, env, sym, info.bound());
166       result.put(e.getKey(), new TyVarInfo((IntersectionTy) bound, info.annotations()));
167     }
168     return result.build();
169   }
170 
canonicalizeList( SourceFile source, int position, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<Type> types)171   private static ImmutableList<Type> canonicalizeList(
172       SourceFile source,
173       int position,
174       Env<ClassSymbol, TypeBoundClass> env,
175       ClassSymbol sym,
176       ImmutableList<Type> types) {
177     ImmutableList.Builder<Type> result = ImmutableList.builder();
178     for (Type type : types) {
179       result.add(Canonicalize.canonicalize(source, position, env, sym, type));
180     }
181     return result.build();
182   }
183 }
184