public c.ty.Type refine(TypeDef typeCtx, MethodDef methodCtx) {
        if (genericArgs.length == 0) {
            if (methodCtx != null) {
                int index = methodCtx.genericParamIndex(rawType);
                if (index != -1)
                    return new c.ty.MethodGenericType(index);
            }
            if (typeCtx != null) {
                int index = typeCtx.genericParameterIndex(rawType);
                if (index != -1)
                    return new c.ty.TypeGenericType(index);
            }
        }

        RawType refinedRawType = typeCtx.qualifyType(rawType);
        c.ty.Type[] refinedGenericArgs = new c.ty.Type[genericArgs.length];
        for (int i = 0; i < refinedGenericArgs.length; ++i)
            refinedGenericArgs[i] = genericArgs[i].refine(typeCtx, methodCtx);

        TypeDef rawTypeDef = Project.singleton.typeDefs.get(refinedRawType);
        if (genericArgs.length != rawTypeDef.genericParams.length)
            throw new NiftyException(
                    "%s was given %d generic arguments; expecting %d.",
                    refinedRawType, genericArgs.length, rawTypeDef.genericParams.length);

        return new c.ty.ParameterizedType(refinedRawType, refinedGenericArgs);
    }