Exemple #1
0
		ValueArray Alias::selfTemplateArgs() const {
			ValueArray templateArgs;
			templateArgs.reserve(templateVariables().size());
			
			for (const auto templateVar: templateVariables()) {
				// Refer to the template variables of this type alias.
				templateArgs.push_back(templateVar->selfRefValue());
			}
			
			return templateArgs;
		}
Exemple #2
0
		bool MethodSetElement::operator==(const MethodSetElement& methodSetElement) const {
			return templateVariables() == methodSetElement.templateVariables() &&
				constPredicate() == methodSetElement.constPredicate() &&
				noexceptPredicate() == methodSetElement.noexceptPredicate() &&
				requirePredicate() == methodSetElement.requirePredicate() &&
				returnType() == methodSetElement.returnType() &&
				parameterTypes() == methodSetElement.parameterTypes() &&
				isStatic() == methodSetElement.isStatic();
		}
Exemple #3
0
		Value Alias::selfRefValue(ValueArray templateArguments) const {
			assert(templateArguments.size() == templateVariables().size());
			if (type()->isBuiltInTypename()) {
				const auto aliasRef = selfRefType(std::move(templateArguments));
				return Value::TypeRef(aliasRef, type()->createStaticRefType(aliasRef));
			} else {
				return Value::Alias(*this, std::move(templateArguments));
			}
		}
Exemple #4
0
		std::size_t MethodSetElement::hash() const {
			std::size_t seed = 0;
			
			boost::hash_combine(seed, templateVariables().hash());
			boost::hash_combine(seed, constPredicate().hash());
			boost::hash_combine(seed, noexceptPredicate().hash());
			boost::hash_combine(seed, requirePredicate().hash());
			boost::hash_combine(seed, isStatic());
			boost::hash_combine(seed, returnType());
			
			for (const auto& parameterType: parameterTypes()) {
				boost::hash_combine(seed, parameterType);
			}
			
			return seed;
		}
		SEM::TypeInstance* AddTypeInstance(Context& context, const AST::Node<AST::TypeInstance>& astTypeInstanceNode, const SEM::ModuleScope& moduleScope) {
			const auto parentNamespace = context.scopeStack().back().nameSpace();
			
			const auto& typeInstanceName = astTypeInstanceNode->name;
			
			const Name fullTypeName = parentNamespace->name() + typeInstanceName;
			
			// Check if there's anything with the same name.
			const auto iterator = parentNamespace->items().find(typeInstanceName);
			if (iterator != parentNamespace->items().end()) {
				const auto& existingTypeInstance = iterator->second.typeInstance();
				const auto& debugInfo = *(existingTypeInstance.debugInfo());
				throw ErrorException(makeString("Type instance name '%s', at position %s, clashes with existing name, at position %s.",
					fullTypeName.toString().c_str(), astTypeInstanceNode.location().toString().c_str(),
					debugInfo.location.toString().c_str()));
			}
			
			const auto typeInstanceKind = ConvertTypeInstanceKind(astTypeInstanceNode->kind);
			
			// Create a placeholder type instance.
			std::unique_ptr<SEM::TypeInstance> semTypeInstance(new SEM::TypeInstance(context.semContext(), fullTypeName.copy(), typeInstanceKind, moduleScope.copy()));
			
			if (semTypeInstance->isPrimitive()) {
				semTypeInstance->setPrimitiveID(context.sharedMaps().primitiveIDMap().getPrimitiveID(typeInstanceName));
			}
			
			switch (moduleScope.kind()) {
				case SEM::ModuleScope::INTERNAL: {
					if (semTypeInstance->isClassDecl()) {
						throw ErrorException(makeString("Definition required for internal class '%s', at location %s.",
							fullTypeName.toString().c_str(), astTypeInstanceNode.location().toString().c_str()));
					}
					break;
				}
				case SEM::ModuleScope::IMPORT: {
					if (semTypeInstance->isClassDef()) {
						throw ErrorException(makeString("Implementation not allowed of imported class '%s', at location %s.",
							fullTypeName.toString().c_str(), astTypeInstanceNode.location().toString().c_str()));
					}
					break;
				}
				case SEM::ModuleScope::EXPORT: {
					if (semTypeInstance->isClassDecl()) {
						throw ErrorException(makeString("Definition required for exported class '%s', at location %s.",
							fullTypeName.toString().c_str(), astTypeInstanceNode.location().toString().c_str()));
					}
					break;
				}
			}
			
			semTypeInstance->setDebugInfo(Debug::TypeInstanceInfo(astTypeInstanceNode.location()));
			
			// Add template variables.
			size_t templateVarIndex = 0;
			for (const auto& astTemplateVarNode: *(astTypeInstanceNode->templateVariables)) {
				const auto& templateVarName = astTemplateVarNode->name;
				// TODO!
				const bool isVirtual = (typeInstanceName == "__ref");
				const auto semTemplateVar =
					new SEM::TemplateVar(context.semContext(),
						fullTypeName + templateVarName,
						templateVarIndex++, isVirtual);
				
				const auto templateVarIterator = semTypeInstance->namedTemplateVariables().find(templateVarName);
				if (templateVarIterator != semTypeInstance->namedTemplateVariables().end()) {
					throw ErrorException(makeString("More than one template variable shares name '%s' in type '%s', at location %s.",
						templateVarName.c_str(), fullTypeName.toString().c_str(),
						astTemplateVarNode.location().toString().c_str()));
				}
				
				semTemplateVar->setDebugInfo(makeTemplateVarInfo(astTemplateVarNode));
				
				semTypeInstance->templateVariables().push_back(semTemplateVar);
				semTypeInstance->namedTemplateVariables().insert(std::make_pair(templateVarName, semTemplateVar));
			}
			
			if (semTypeInstance->isUnionDatatype()) {
				for (auto& astVariantNode: *(astTypeInstanceNode->variants)) {
					const auto variantTypeInstance = AddTypeInstance(context, astVariantNode, moduleScope);
					variantTypeInstance->setParent(semTypeInstance.get());
					variantTypeInstance->templateVariables() = semTypeInstance->templateVariables().copy();
					variantTypeInstance->namedTemplateVariables() = semTypeInstance->namedTemplateVariables().copy();
					semTypeInstance->variants().push_back(variantTypeInstance);
				}
			}
			
			if (!astTypeInstanceNode->noTagSet.isNull()) {
				SEM::TemplateVarArray noTagSet;
				
				for (const auto& astNoTagName: *(astTypeInstanceNode->noTagSet)) {
					const auto templateVarIterator = semTypeInstance->namedTemplateVariables().find(astNoTagName);
					if (templateVarIterator == semTypeInstance->namedTemplateVariables().end()) {
						throw ErrorException(makeString("Can't find template variable '%s' in notag() set in type '%s', at location %s.",
										astNoTagName.c_str(), fullTypeName.toString().c_str(),
										astTypeInstanceNode->noTagSet.location().toString().c_str()));
					}
					
					noTagSet.push_back(templateVarIterator->second);
				}
				
				semTypeInstance->setNoTagSet(std::move(noTagSet));
			}
			
			const auto typeInstancePtr = semTypeInstance.get();
			
			parentNamespace->items().insert(std::make_pair(typeInstanceName, SEM::NamespaceItem::TypeInstance(std::move(semTypeInstance))));
			
			return typeInstancePtr;
		}
Exemple #6
0
		const Type* Alias::selfRefType(ValueArray templateArguments) const {
			assert(templateArguments.size() == templateVariables().size());
			return Type::Alias(*this, std::move(templateArguments));
		}
Exemple #7
0
		SEM::Value GetTemplatedMethodWithoutResolution(Context& context, SEM::Value value, const SEM::Type* const type, const String& methodName, SEM::ValueArray templateArguments, const Debug::SourceLocation& location) {
			assert(value.type()->isRef() && value.type()->isBuiltInReference());
			if (!type->isObjectOrTemplateVar()) {
				throw ErrorException(makeString("Cannot get method '%s' for non-object type '%s' at position %s.",
					methodName.c_str(), type->toString().c_str(), location.toString().c_str()));
			}
			
			const auto methodSet = getTypeMethodSet(context, type);
			const auto& objectConstPredicate = methodSet->constPredicate();
			
			const auto canonicalMethodName = CanonicalizeMethodName(methodName);
			const auto methodIterator = methodSet->find(canonicalMethodName);
			
			if (methodIterator == methodSet->end()) {
				throw ErrorException(makeString("Cannot find method '%s' for type '%s' at position %s.",
					methodName.c_str(),
					type->toString().c_str(),
					location.toString().c_str()));
			}
			
			const auto& methodElement = methodIterator->second;
			if (methodElement.isStatic()) {
				throw ErrorException(makeString("Cannot access static method '%s' for value of type '%s' at position %s.",
					methodName.c_str(),
					type->toString().c_str(),
					location.toString().c_str()));
			}
			
			auto templateVariableAssignments = type->generateTemplateVarMap();
			
			const auto function = type->isObject() ? type->getObjectType()->functions().at(canonicalMethodName).get() : nullptr;
			
			if (function != nullptr) {
				const auto& templateVariables = function->templateVariables();
				if (templateVariables.size() != templateArguments.size()) {
					// Try to apply some basic deduction...
					if (templateVariables.size() == 1 && templateArguments.size() == 0 &&
						function->constPredicate().isVariable() &&
						function->constPredicate().variableTemplateVar() == templateVariables[0]
					) {
						const auto boolType = getBuiltInType(context, context.getCString("bool"), {});
						templateArguments.push_back(SEM::Value::PredicateExpr(objectConstPredicate.copy(), boolType));
					} else {
						throw ErrorException(makeString("Incorrect number of template "
							"arguments provided for method '%s'; %llu were required, "
							"but %llu were provided at position %s.",
							function->name().toString().c_str(),
							(unsigned long long) templateVariables.size(),
							(unsigned long long) templateArguments.size(),
							location.toString().c_str()));
					}
				}
				
				// Add function template variable => argument mapping.
				for (size_t i = 0; i < templateArguments.size(); i++) {
					const auto templateVariable = templateVariables.at(i);
					const auto& templateValue = templateArguments.at(i);
					
					if (templateValue.isTypeRef()) {
						const auto templateTypeValue = templateValue.typeRefType()->resolveAliases();
						
						if (!templateTypeValue->isObjectOrTemplateVar() || templateTypeValue->isInterface()) {
							throw ErrorException(makeString("Invalid type '%s' passed "
								"as template parameter '%s' for method '%s' at position %s.",
								templateTypeValue->toString().c_str(),
								templateVariable->name().toString().c_str(),
								function->name().toString().c_str(),
								location.toString().c_str()));
						}
						
						templateVariableAssignments.insert(std::make_pair(templateVariable, SEM::Value::TypeRef(templateTypeValue, templateValue.type())));
					} else {
						templateVariableAssignments.insert(std::make_pair(templateVariable, templateValue.copy()));
					}
				}
			} else {
				assert(templateArguments.empty());
			}
			
			const auto methodConstPredicate = methodElement.constPredicate().substitute(templateVariableAssignments);
			
			if (!objectConstPredicate.implies(methodConstPredicate)) {
				throw ErrorException(makeString("Cannot refer to mutator method '%s' from const object of type '%s' at position %s.",
					methodName.c_str(),
					type->toString().c_str(),
					location.toString().c_str()));
			}
			
			// Now check the template arguments satisfy the requires predicate.
			const auto& requirePredicate = methodElement.requirePredicate();
			
			// Conservatively assume require predicate is not satisified if result is undetermined.
			const bool satisfiesRequireDefault = false;
			
			if (!evaluatePredicateWithDefault(context, requirePredicate, templateVariableAssignments, satisfiesRequireDefault)) {
				throw ErrorException(makeString("Template arguments do not satisfy "
					"require predicate '%s' of method '%s' at position %s.",
					requirePredicate.substitute(templateVariableAssignments).toString().c_str(),
					methodName.c_str(),
					location.toString().c_str()));
			}
			
			if (function != nullptr) {
				const auto functionType = simplifyFunctionType(context, function->type().substitute(templateVariableAssignments));
				const auto functionRefType = createFunctionPointerType(context, functionType);
				
				auto functionRef = addDebugInfo(SEM::Value::FunctionRef(type, function, std::move(templateArguments), functionRefType), location);
				
				if (type->isInterface()) {
					const auto interfaceMethodType = createInterfaceMethodType(context, functionType);
					return addDebugInfo(SEM::Value::InterfaceMethodObject(std::move(functionRef), std::move(value), interfaceMethodType), location);
				} else {
					const auto methodType = createMethodType(context, functionType);
					return addDebugInfo(SEM::Value::MethodObject(std::move(functionRef), std::move(value), methodType), location);
				}
			} else {
				const bool isTemplated = true;
				const auto functionType = methodElement.createFunctionType(isTemplated);
				const auto functionRefType = createFunctionPointerType(context, functionType);
				auto functionRef = addDebugInfo(SEM::Value::TemplateFunctionRef(type, methodName, functionRefType), location);
				
				const auto methodType = createMethodType(context, functionType);
				return addDebugInfo(SEM::Value::MethodObject(std::move(functionRef), std::move(value), methodType), location);
			}
		}
Exemple #8
0
		MethodSetElement MethodSetElement::withNoExceptPredicate(Predicate newNoExceptPredicate) const {
			return MethodSetElement(templateVariables().copy(), constPredicate().copy(),
				std::move(newNoExceptPredicate),
				requirePredicate().copy(),
				isStatic(), returnType(), parameterTypes().copy());
		}
Exemple #9
0
		MethodSetElement MethodSetElement::withRequirement(Predicate requirement) const {
			return MethodSetElement(templateVariables().copy(), constPredicate().copy(),
				noexceptPredicate().copy(),
				Predicate::And(requirePredicate().copy(), std::move(requirement)),
				isStatic(), returnType(), parameterTypes().copy());
		}
Exemple #10
0
		MethodSetElement MethodSetElement::copy() const {
			return MethodSetElement(templateVariables().copy(), constPredicate().copy(),
				noexceptPredicate().copy(),
				requirePredicate().copy(),
				isStatic(), returnType(), parameterTypes().copy());
		}